分類
發燒車訊

一個生物專業學生的內心獨白:我為什麼能去互聯網大廠?

這回,考慮到近期關注了許多新朋友,並且大多都是學生黨,可能對我還不是特別熟悉。因此我決定重新把我從非科班如何通過自學(狗屎運)進入大廠的經歷分享出來,希望能夠給予一些將要面臨秋招,或者將要準備進入互聯網行業的同學一丟丟的幫助。

早期關注我的讀者可能都約莫着記得,我是在華科讀的本碩,專業是生物醫學工程。雖說專業的的確確是帶了生物二字,但是我老實交代,實際上並不是純粹的生物技術方向上的專業。簡單科普一下:

生物醫學工程是屬於交叉程度非常高,主要面向生物醫學領域的工程學科。我們在學校的主要課程包含硬件設計、軟件設計、生化基礎以及儀器科學等。

所以呢,原諒本文的些許標題黨。但是說實話,由於學科高度交叉,我們實際上所習得的技能就是一團漿糊。在計算機科學方面的系統知識積累,與純生物專業相比,也不過是五十步笑百步。

一 啟智階段

雖說大學期間學的都不是計算機,但是我對計算機的興趣萌芽卻是十分的早。那估計都得有二十年前了,嗯誇張了點。不過應該是在小學時候了。

我是在老家鄉下上的小學,你們可能想象不到,那個時候的鄉下小學竟然都有電腦課。不過那時候不叫電腦課,叫做“微機課”。

微機課是幹嘛的呢?就是一群小朋友排排隊,拖鞋進到一個乾淨的房間里,然後幾個人圍着一台那種屁股又大又方的電腦,玩紙牌。沒錯,就是windows上流行多年的紙牌遊戲。

怎麼說呢。我玩紙牌賊溜。 大概天生對這一類東西的接受能力比較強,所以上手很快,並且除了紙牌,還有空當接龍,掃雷,3D彈球。這麼說可能有點暴露年齡了。

最早windows系統普及的這一批遊戲真的讓我對“微機”這麼個東西產生了懵懂的概念和持續的嚮往。

二 本科階段

之後的成長道路中,一直對計算機耍的挺溜。但是有點尷尬的是,沒人領進門。所以一直都是在娛樂,並沒有真正意義上接觸到計算機內部或者代碼編程的世界。

初識代碼

所以在上大學之前,基本上對編程一無所知,但是卻有一種強烈的對計算機的熱愛。不過那時對於計算機的理解僅限於【裝系統】,【裝軟件】和【拆洗主機風扇】。不要問我為什麼沒有去學計算機,要怪就只能怪考試時坐在我旁邊的那位,大概天生就得了瘋狂抖腿病的二貨。氣!

一不小心,還進了生科院。但是緣分這種東西,真的妙不可言。這一切的開始源於一場面試。

所在的大學是一所以工科著稱的高校,其中創業氣氛十分濃厚。學校因此有許多小有名氣的科創團隊,基本上是由老師主導,各專業學生組成的小團體。可不要小看這些小團隊,世界級程序設計大賽的獎牌獲得者經常就出於此類團隊。剛上大學的我們單純稚嫩,自然會被被這些團隊的大幅宣傳報和滿目的獎牌稱號所吸引膜拜。我也不例外。

當時我便懷着澎湃的心情申請了一家曾多次在微軟創新杯奪得金獎的團隊。一個從鄉下來的小伙,第一次參加面試,第一次單獨和碼農小姐姐夜晚座談,第一次參加所謂的通宵測試。

也就是在那一個晚上,開啟了我新世界的大門。

那天晚上給我一群編程小白的任務,是模仿百度首頁,實現整個網頁的設計、布局和基本鏈接。提前給出的提示是w3c的教程網址。

從來沒有接觸過編程的我在此之前,連編程的流程都不清楚,更不必說編譯環境、編譯語言甚至是源代碼閱讀(當然這個任務也涉及不到這些)。

但是也就是那一個晚上,讓我真正意義上的接觸了敲代碼這個事兒。

沒錯,我的編程起點是HTML+CSS。可惜的是,我並沒有通過那個團隊最終的面試。不過從那以後,我就開始了網站開發的自學之路。

個人自學的堅持很大程度上基於興趣,源於在室友面前一頓裝逼后的成就感。但這就是一個生科院的學生在課後的最大樂趣所在。

小試牛刀

在接觸到網站開發之後,從最初的HTML+CSS到後來的HTML5+CSS3+JS+ASP,從靜態頁面的布局到動態網頁的請求。

雖然感覺技術的成長也就是從博客的複製粘貼走向了文檔的複製粘貼。但是終於迎來了小試牛刀的機會。

學校某大型學校組織需要做一個展示網站,朋友拉上了我和幾個人承擔了這個事情。這算是第一次真正意義上的項目開發,不過整個網站的功能不多,主要還是展示為主,後台也直接通過學校網絡平台整合就行了。所以整體下來做的事情並不多。

迷茫困惑

一直以來,都是自己通過博客自學,東拼西湊的建立起知識架構。但是其實技術基礎十分不牢固,不懂計算機基礎、計算機網絡,更別說編譯原理、操作系統等基本的知識。因此在很長一段時間內,覺得好像也沒有會什麼,一直對自己的能力保持懷疑。

在這段時間內,有過跑去搞嵌入式,硬件開發,甚至是產品設計、界面設計,視頻製作。但都不一而終。

一段迷茫,一段頹廢。一不小心就成為校園裡的學長,於是開始緊緊茫茫的尋找實驗室。

新的方向

好在我們專業與生科院其它專業相比,還是帶有工科氣質的。醫學影像學本身就是這個專業最為重要的一個方向。因此懷着對編程的興趣,加入了一個專門做醫學影像的實驗室。

進入實驗室,不再是之前的漫無目的,隨處拾荒,但卻也並不會接觸到前沿新興的技術。畢竟在實驗室里,工程技術更多的只是工具。

不過值得一提的是,在實驗室里,我接觸到了算法思想。醫學圖像本來就是圖像處理領域的一大分支,因此圖像處理算法的了解同樣也是至關重要。

從這個時候開始,我已經不再搞網站開發那一套東西,專心使用C++寫我的算法。那時候深度學習還沒那麼熱門,大多數的圖像處理方式還是基於傳統的算法進行。雖然算法能力薄弱,但是倒也是我所求。

同時,為了獲得數據,還接觸到Linux系統以及一些腳本,在做研究的過程中也大大增加自己的技術面。

與此同時,為了鞏固自己的一些技術基礎,也為了督促自己的學習,我報考了計算機等級考試和國家軟考。可能對於計算機專業的學生來說,沒有什麼含金量,輕而易舉。但是對於一個非科班的學生而言,這樣的考試可以很大程度上幫助自己去重新組織零碎的知識。畢竟不是所有人都有足夠的精力去跟着計算機系的人上課。

本科階段的經歷讓我知道自己與計算機系的差距,雖然接觸了許多東西,但是也都不夠精,甚至沒有底氣去獨立承擔一個小的開發任務。

因此最終選擇了讀研。希望讓自己的技術都夠在某一個點上精進,能夠獨立的做出點東西來。當然最終的結果可能並不是自己當初所想,但是說到底還是得感謝在研究生期間所做出的努力。

三 碩士階段

我研究生的生活是從大四就開始的。因為是本校保研生,所以在大三下確定好實驗室后,基本就直接開始搬磚的苦逼生活了。當然舍友和同學在為畢業而慶祝歡快的時候,我就開始在實驗室早出晚歸。

讀研的開始

進入實驗室之後,剛開始一段時間也是沒有人帶。這能靠自己去多多實驗室專業方向的文章,然後學一點基本技能。更重要的其實是為了在實驗室混個臉熟。

實驗室的研究方向主要是核醫學成像系統,整個系統的搭建涉及到核科學研究、物理數學模型的建立、电子信息的數據獲取、自動化控制設計、机械結構設計、軟件和算法處理以及醫學實驗驗證等一系列的過程。

但對我們個人來說,主要是做某一個方向即可。當時我還是自認有一些編程基礎,於是計劃去做軟件開發或者數據處理的方向。但是最初期是沒有人帶的,所以就花三天時間自學了python3,把廖雪峰的python教程從頭到尾走了一遍。

可惜的是,學完之後也並沒有派上用場。

之後實驗室新項目確立,我被導師安排到了一個新項目組裡。在項目組中,主要負責的是圖像重建的部分。圖像重建是醫學影像領域非常重要的一個研究方向,目的是將影像系統採集到的多維多尺度的信息根據成像原理,依照不同算法還原成二維或三維的斷層圖像。所以本質上來說,圖像重建的重點也是在於算法設計和優化。

方向的多變

開始所在的項目組內,主要的工作還是基於軟件編程和算法開發,涉及到的技術棧主要還是以C++為主,然後加上一些圖型庫,如QtopenGLVTK等等。不過都是處於調用函數調包的階段,也沒有很深入的研究算法原理和實現機制。實話說其實個人提升不大。

過了一段時間后,實驗室師兄拉我去幫他做事。師兄本身能力非常出眾,科研水平不容置疑,所以當時就過去了。之後在他手下做的事就很多變了,不只是軟件開發,還涉及到数字電路編程,PCB制板,系統仿真等。

那個時候還來實驗室沒多久,沒有仔細的想過自己之後的就業方向,只想着能夠在研究生期間多做些成果,多發文章。因此,跟着師兄搬磚的時候也沒有過多考慮對之後的求職是否有幫助,只是想把事情做好,做出有意義的成果。

不過幸運的是,在大四暑假前,也就是研究生入學之前。根據師兄的指導,將一個軟件開發的工作給擴充,投了一篇領域內的頂會。雖然覺得所作的工作沒什麼特別的,但是最終文章被錄還是非常開心的。也正因為這個事,之後更想着能夠多發文章多出成果。同時,師兄也比較會熬雞湯,各種說辭讓我放佛感覺到即將成為科研巨人,登上學校官網,走上人生巔峰。

綜合能力鍛煉

在實驗室,除了完成自己的科研任務,還有很重要的一部分,就是寫本子。也就是申請項目基金等等文字工作。

我估計有參与過的項目申請或結題工作不下十餘項,每次都會涉及到大量文字的整理、表達、排版等工作。一般的學生對於這樣的工作都是極度排斥的,覺得很煩又沒什麼用。當然我也是這樣覺得的。

只不過在寫了大量的本子後會發現,其實這也是綜合能力的鍛煉。我們導師常說,博士生一定要會寫項目,碩士生的話盡量寫。說明他把這也是當作一種能力的培養。在師兄手下,我也經常性的寫本子,甚至於超過了敲的代碼。那時候也沒有很明確的技術培養規劃,所以倒也覺得還行。

獨自前行

只不過好景不長。帶我的師兄由於過於優秀,將要離開實驗室去其它高校就職。這對當時的我來說,處境有些許尷尬。因為我的研究方向是與師兄的工作有交叉的,同時一些設備和材料也需要師兄的支持。

實驗室本身的氛圍是以博士帶頭,碩士輔助進行項目開展的,而我的研究方向是我自己獨立出來的一個題目。說白了就是實驗室就我一個人在搞這個,但是這個方向不是導師關注的方向。

因此,在這之後,我又回歸到了一個人做事的階段。大概是研一下開始,我就只能自己一個人去想自己的研究課題,偶爾會跟老師討論,但是也沒有很確定的工作路線。具體的工作內容也只能靠自己去思索。

在這段期間,我寫過verilog,調過FPGA,畫過板子,畫過工程圖,當然也寫過軟件做過算法。一個人做事的話,可以說是很自由,沒有老師管,也沒有報告的壓力。只是很多時候發現有一些想法沒辦法實現,也無法對前沿領域有很深的洞察。空有一腔發文章報效實驗室的熱血,卻發現像是站在水中的浮木上,搖搖欲墜。當然這其中,個人的問題佔有很大比重。

摸魚的日子

不敢說自己的有多麼自律,多麼出色。可能世上大多人都是芸芸眾生,我也不過一個普通人。在自己做研究的同時,每次到臨近頂會收集文章摘要之時,我都會很积極的熬個一兩個月,將自己的想法和結果寫成一到兩篇的會議文章。我自己也大概知道其實工作沒有太大的突破點,但也是希望能夠賭一把。

只不過兩年來,一共整理出數篇會議摘要,都沒有被同意投稿。每一次還是會有些灰心,也有些不服。會時刻回想起導師的反饋,而後想到一堆反駁的理由。只不過都沒用。

每一次之後,都會有一段時間的消沉。不太想去實驗室,不太想看論文,在實驗室可能也就是摸摸魚罷了。很多時候覺得鬥志滿滿,又會瞬間像泄了氣的皮球,沒有精力去完成任何事。

職業方向

到如今,算是大四的時光,在實驗室已經呆了快四年。平心而論,沒有做過什麼突出的成果,也沒有練就什麼出色的技術。研究生活高開低走,一度以為自己是什麼科研巨星,後來僅剩的一絲熱情也在導師的「也沒看出你有什麼天分」中黯然消逝。不過還好,在這之前,我找到了自己的職業方向。

我本身就是一個比較後知后覺的人,一方面是懶,另一方面又對自己有一種迷之自信。我真正意義上開始準備校招還是在去年六月底七月初的時候,也就是研二下學期快結束的時候吧。我們實驗室的碩士生出去基本就是兩個方向,軟件或者硬件。搞電路的基本都選擇去做硬件開發,其它的大部分都會選擇做軟件。我也沒啥可想的,雖然做過硬件,但是技術水平根本不敢出手。所以求職的方向直接就定在了軟件開發相關。

當時還不知道應聘互聯網還要刷題,還要複習,以為上去介紹下自己,講講自己做的跟互聯網沒有半毛錢關係的項目就可以顯得很有想法的樣子。後來真正開始準備的時候才發現,自己原來還差得有點遠。

老實說在研究生期間,主要使用C++Matlab,主要的項目就是用Qt寫了一個客戶端,裏面有網絡通信的模塊可以對數據做一些處理,並且能夠显示圖譜。用Matlab主要就是做了一些比較基礎的圖像處理和機器學習的算法。光這項目再加上非科班帶「生物」二字的專業,的確讓不清楚的人會十動然拒。

不過其實也沒得選擇。生醫專業對口的公司都是做醫療器械,比如聯影、邁瑞等。但是其實去這些公司也是做軟件開發工程師。相對來說,互聯網公司技術好,待遇好,發展好,自然就成為大部分的選擇去向。

說是跨行,但是其實也沒有別的更好的選擇。我們老師常說希望我們學生以後能夠在我們這個領域發光發熱。這倒是真的,國家的發展還是離不開這些能夠在某個領域深耕的人,而不是為了一昧追求熱點和高薪而忘記了初心。

四 求職經歷

講講我的秋招經歷吧。我的秋招雖然準備的晚,但是其實還是挺順利的。從19年8月開始接到面試,2個月內已經拿到了15+的offer,基本平均薪資都在30w+。包括抖音美團華為小米等等。那段時間真的是狀態上來了,就是佛擋殺佛,神擋殺神。

不過剛開始的時候,由於實驗室的原因,沒有辦法出去實習。甚至由於一些原因,一直拖到暑期前才開始準備複習。

那時已經快七月初了。急匆匆的登上各種學習網站,發現這也太多要看了的吧,還得刷題。關鍵一看面經,這都啥呀。還要手撕代碼的嗎?

這一看當時不要緊,關鍵晚上就焦慮的快睡不着了。每天都在想應該怎樣複習,怎麼寫簡歷,沒有項目該怎麼辦。

剛開始的時候連簡歷都不敢投,因為老覺得簡歷一過去就會安排面試。後來發現這完全就是多慮了。大概從七月初我就開始投簡歷,因為七八月是一些公司提前批招聘的階段。

許多非科班的學生,在投遞簡歷的時候才能發現自己的無助。我在簡歷投遞初期,基本沒有任何反饋。提前批階段,許多公司都會去爭奪更優秀的簡歷候選者,對於生物專業的學生真的沒有什麼優勢。

但是沒有關係,既然選擇了這條路,那麼就要堅持下去。投一家無人應答,那麼就投十家,投五十家。我在整個秋招階段,總共投遞過近一百家公司。許多在提前批沒有給予反饋的公司,後期大部分都有電話聯繫重新開啟面試流程。所以,就算認為自己的簡歷再不夠出色,也要相信總會有瞎了眼的HR(誤)。

我當時一直在堅持投簡歷,只要看到的招聘信息都會去投遞。還記得第一次做測評題的時候都非常緊張,以為這就是筆試題。非常認真的拿紙筆在計算,慌的不行。

後來直到八月初才收到第一份面試邀請,多益網絡。當時約了面試之後簡直怕死了,雖然說複習了一個月大部分的 C++ 基礎知識都看得差不多了,但是肯定是不夠的。面試的時候面試小哥全程就低頭照着題庫念,也不看我。我這邊的音頻信號也不太行,他那邊說話都聽不清楚。兩個人就在無數次的重複和確認。關鍵是面試完之後我自我感覺還非常良好。

最終結果還是掛了,說實話打擊挺大的,感覺因此對面試產生了恐懼。不過後來試着自己跟自己講解,慢慢的也習慣了面試的感覺。

隨後在八月底的時候,終於收穫了第一家 ihandy 的 offer。並且在進行總管面的時候,跟面試官進行了深入的交談。面完之後讓我有一種都不好意思拒絕這家公司的念頭。這也是第一次感受到了面試官的認可。

隨後,便一發不可收拾。這個時候,已經準備了大概兩個月,基本的技術知識我都看完了,劍指 offer 上的66題以及 leetcode 上基本的題也大概刷了兩次。同時獲得了一個 offer 之後,對自己的認可度非常高,使得面試的狀態非常好。

後來給了面試機會的公司基本都拿到了 offer。像字節跳動、美團、虎牙等等公司,面完的感覺就是基本穩了。不過可惜的是阿里簡歷面后,內推人開始說通過了,後來不知道什麼情況流程就拖到結束了。

騰訊也一直沒有撈過我面試。感覺如果在狀態頂峰的情況下能有面試機會的話,還是很有希望的。不過也說明簡歷依然不夠出色,非科班沒有實習經歷,項目也比較水,導致AT大廠連面試機會都沒給。這也是秋招比較遺憾的地方。

另外,記住面試過程,跟投遞簡歷一樣,一定要多面多總結。

如果你的表達能力不好,沒有別的好的辦法,只能多練。自己在面試前問自己問題,然後用自己的話陳述出來。甚至是錄音自己聽,感覺一下面試官聽到你的回答是做何感想。

心態要好。面試官也是人,不可能所有人都能夠絕對公平的跟你面試,所以遇到人品不好的面試官,做好自己就行了。

要善於總結。每一次的面試都可以做好記錄,錄音或者筆記都可以。面試完之後需要多回顧,發現自己的錯誤,感受面試官對你的引導,然後下次面試注意。我一般喜歡用印象筆記記錄東西,每一次的面試記錄我都記錄在印象筆記上。電腦手機都可以看,即使是出門現場面試也不怕。

最後就是一定要堅持下去。金九銀十,金三銀四。把握好機會,要善於規劃自己的成功。

五 複習準備

想進互聯網的技術崗,基本都是要提前準備的。當然某些大佬及大大佬除外。無論是校招還是社招,都需要針對自己的求職崗位進行必要的理論知識複習、項目經歷反思和算法能力訓練。只不過校招會偏向於基礎和算法能力,社招可能都會重點考察。

除項目經歷外,複習的階段主要分為語言基礎、數據結構和算法、計算機網絡、操作系統、數據庫以及算法刷題。

語言基礎:

以 C++ 為主。我不喜歡看又厚又重的語言書,因此複習全程是以博客、開發文檔和實踐相結合的方式進行技術點複習。C++ 的技術點相對於其它語言來說,不算多,也不算難。技術重點的篩選可以從面經中提取而來。當然每一屆都差不多,所以找找別人總結好的資料看就行。(想要我複習資料的,可關注公眾號後台回復秋招領取)

數據結構和算法:

這應該是編程的基礎,重要需要了解的數據結構不出10種。花點時間弄清楚它們的原理、結構和使用方法,常用的操作也需要掌握。最難不過紅黑樹。

這裏的算法指的是常用的算法,比如排序、遍歷,與數據結構相結合的數據操作方式。需要保證手寫才行。

計算機網絡:

網絡部分的內容其實可以算是最重要的,無論是前端後端都需要掌握網絡通信過程中的操作和機制。技術點可參考網絡服務器的請求和響應過程。將其中所有涉及到的協議、機制了解清楚,就可以掌握大部分了。

操作系統:

如果有Linux使用經歷和腳本編程基礎在面試中會很加分。對於操作系統的理解建議按照Linuxwindos系統的區分進行。

數據庫:

SQL基本操作必須要掌握,還包括一些關係型數據庫的基本原理和機制,內容不多,多看看就可以掌握。

Redis同樣也是加分項,有能力的可去研究下源碼。

算法刷題

這一部分不多說,普通人只能勤能補拙。無論是劍指offer66題還是leetcode都可以,劍指刷兩遍,leetcode兩百題,基本沒有問題了。刷題時不要死刷,可以根據類型刷,比如鏈表操作、二叉樹操作、動態規劃等。相同類型重複做,能夠更好的培養算法思想。

六 感想體會

說起求職的過程,其實真要我來評價的話,估計運氣是佔了一大部分,連我這樣都行,你們也可以的。不過最終能夠獲得一些互聯網公司認可的原因,我認為主要有以下幾點原因吧:

1.本科階段接觸互聯網行業比較早,對於這個行業有自己的見解。

2.本科階段有考過一些計算機水平的證書,大概系統的學了一下計算機相關的基礎知識。

3.用C++比較多,對語言基礎的理解比較好。

4.面試狀態比較好,比較會表達自己的想法。

5.學習能力還行,能夠在面試官的引導下找到他想問的技術點。

6.準備過程比較有規劃,能夠快速的掌握面試的重點。

7.人長得老實,比較容易獲得信任感。(這個你們可能學不了^_^)

8.比較幸運。

前天剛碩士答辯完,這两天也把學位申請的各種材料提交上去了。一不小心,七年的大學校園時光真的要結束了,兜兜轉轉感覺好像依舊是一無是處,一事無成。但是依舊希望以後能夠:

二龍騰飛、三羊開泰、四季平安、 五福臨門、六六大順、七星高照、八方來財、九九同心、十全十美、百事亨通、千事吉祥、萬事如意

人生無常,活在當下,且行且珍惜!

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

希臘野火竄燒 波及著名邁錫尼古城遺址

摘錄自2020年8月31日中央社報導

希臘青銅時代的著名遺址邁錫尼古城附近野火延燒,當局緊急疏散遊客,消防官員表示,火勢已獲得控制。

希臘消防部門官員表示,野火下午從阿卡曼儂(Agamemnon)古墓附近竄起,「部分已獲得控制」。

伯羅奔尼梭(Peloponnese)南部的消防局局長科利維拉斯(Thanassis Koliviras)告訴「雅典通訊社」(Athens News Agency),大火波及「考古遺址的一個區塊,並燒毀些許乾草,但沒有損及博物館」。

希臘文化部發表聲明說,根據初步調查,「大火沒有破壞古蹟」,並說之後「一組專家將評估受損情況」。

乾燥的夏季氣候期間,希臘每年都得應付燒不盡的野火,並且高溫時常超過攝氏30度。

氣候變遷
國際新聞
希臘
野火

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

海神挾風雨今晨登陸 南韓一核電廠2機組突停止運轉

摘錄自2020年9月7日自由時報報導

中度颱風「海神」已於台灣時間今(7日)上午8點登陸南韓蔚山沿海,海神颱風威力強大,傳出位於慶尚北道慶州市的月城核電廠有兩個核電機組暫停運轉。

據《韓聯社》報導,韓國水電與核電公司總部宣布,擁有四個核子反應爐發電的月城核電廠的2號機組在當地時間8點38分停止運作,而3號機組則在上午9點18分停止運轉,這兩機組設備容量都達70萬千瓦(kW),另外兩機組則正常運作,維持60%發電量,總部強調,沒有輻射外洩問題。

韓國水電與核電公司總部一名官員表示,目前正在檢查停機原因,研判可能是由於颱風造成電線短路問題;月城核電廠供應約5%的南韓用電量。

能源轉型
國際新聞
南韓
核電廠

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

主動安全很重要 8萬元以下帶ESP家用轎車選這些!

最初的遙控泊車着實讓我們驚艷的一把。速銳在7萬多的車型上就已經配備了ESp車身穩定系統。除了ESp此外,速銳身上還有許多實用配置,表現可圈可點。動力上速銳採用了1。5升的自然吸氣發動機。搭配5擋手動或者6擋雙離合變速箱,最大功率109馬力最大扭矩145牛米,這樣的動力輸出只能說夠用,但是這也為速銳帶來了非常親民的價格。

昨天小編美美走路一不小心,摔了個狗吃屎;這時候二貨同事說,你這種十八年的老車沒有ESp,肯定容易摔跤啊,主動安全性不行嘛。

的確,對於十八歲的小編美美來說,如果我媽生我的時候附帶了ESp技能,興許就不會摔跤了。

看↓↓↓

帶ESp的狗狗穩定性多好。

當然這都是玩笑,不過ESp對於汽車來說還真有這麼神奇的功效。它能夠通過對單獨車輪進行制動、切斷動力等方法來控制車身動態,減少車輛的失控機率。憑藉優異的主動安全表現,ESp榮獲了NCAp全球獎項,這也足以證明ESp在安全性上的巨大作用。

我們看看在時速40km的情況下汽車在冰面上做一個變線的情況

可以看到帶ESp的車輛很好的保持了正常行駛,而沒帶ESp的車,呵呵~

那麼多少錢的車會搭載ESp呢?一般來說10萬以上的自主車輛都配備了ESp,12萬以上的合資車都配備了ESp,如果你買了個合資車花了十幾萬還沒有ESp那你來找我,我來幫你罵它。那麼10萬內有沒有帶ESp的車呢?當然有,這幾台車不到8萬裸車的配置就帶有ESp了,而且綜合表現也不錯哦。

長安悅翔V7

指導價:5.99-8.79萬

長安悅翔V7是我們非常熟悉的一位車型。而最近它又增加了1.0T的動力系統。除了低配車型之外,中高配開始就搭載了ESp車身穩定系統,在安全性方面還是十分厚道的。

悅翔V7的外觀設計在同級別中數一數二,而在內飾上設計的也十分恰到好處。簡約的內飾清晰的功能分區以及不錯的人機設計。都值得豎個大拇指,但是對於悅翔V7來說最大的問題是我為什麼不加一點錢買逸動呢?

比亞迪速銳

指導價:6.99-9.59萬

比亞迪速銳是我們非常熟悉的一款車型,它以超高的配置和大空間作為主要的賣點。最初的遙控泊車着實讓我們驚艷的一把。速銳在7萬多的車型上就已經配備了ESp車身穩定系統。除了ESp此外,速銳身上還有許多實用配置,表現可圈可點。

動力上速銳採用了1.5升的自然吸氣發動機。搭配5擋手動或者6擋雙離合變速箱,最大功率109馬力最大扭矩145牛米,這樣的動力輸出只能說夠用,但是這也為速銳帶來了非常親民的價格。

雪佛蘭樂風RV

指導價:7.49-9.99萬

樂風RV雖然定位為小型車,但是由於兩廂的造型設計以及不錯的空間設計理念,樂風RV在內部空間表現上還是十分值得表揚的,樂風RV使用1.5升自然吸氣發動機匹配5擋手動或者4擋自動變速箱。

樂風RV在同價位的車型中十分罕見的全系標配ESp車身穩定系統,這也显示了通用對於安全性的重視以及嚴謹的造車態度,樂風RV可以說是一位不折不扣的實力选手。不過沒那麼主流的外觀可能會讓不少人拒絕它。

東風風行景逸S50

指導價:6.99-10.29萬

風行景逸S50外觀上就比較的平庸了,在內飾設計上則是東風風行家族的標準化設計,沒什麼亮點但是風行景逸S50在低配車型上也已經配備了ESp,而且加上較大的尺寸和完善的動力系統。風行景逸還是值得推薦的。

風行景逸S50採用1.5L和1.6L/2.0L 3款自然吸氣發動機自動車型匹配CVT變速箱。動力方面風行景逸S50表現平平,但是它的車身尺寸比較大,軸距長達兩米七,行李箱容積也達到了500升,對於家用車來說這樣的空間表現十分寬裕了。而我唯一需要考慮的是我要不要等即將上市的外觀更大氣內飾更加精緻的新款呢?

總結:

對於家用車來說,安全舒適是十分重要的,有ESp能夠大大提升你在下雨天、環島行駛等多種情況下的安全性,因此對於ESp小編美美是十分推薦的,當然更重要的還在於謹慎駕駛安全開車,如果你100km/h打死方向,神仙也救不了你。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

【實戰】基於OpenCV的水表字符識別(OCR)

目錄

  • 1. USB攝像頭取圖
  • 2. 圖像預處理:獲取屏幕ROI
    • 2.1. 分離提取屏幕區域
    • 2.2. 計算屏幕區域的旋轉角度
    • 2.3. 裁剪屏幕區域
    • 2.4. 旋轉圖像至正向視角
    • 2.5. 提取文字圖像
    • 2.6. 封裝上述過程
  • 3. 字符分割,獲取單個字符的圖像
  • 4. 模板匹配:確定字符內容
    • 4.1. make_template
    • 4.2. 模板修復
    • 4.3. 重新加載模板數據
    • 4.4. 模板匹配

1. USB攝像頭取圖

由於分辨率越高,處理的像素就越多,導致分析圖像的時間變長,這裏,我們設定攝像頭的取圖像素為(240,320):

cap = cv2.VideoCapture(0)  # 根據電腦連接的情況填入攝像頭序號
assert cap.isOpened()

# 以下設置显示屏的寬高
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))

這裏提幾個常用的標準分辨率:

  • VGA (Video Graphics Array): 640×480
  • QVGA (QuarterVGA): 240×320
  • QQVGA: 120×160

接下來可以捕獲一幀數據看一下狀態:

# %% 捕獲一幀清晰的圖像
def try_frame():
    while True:
        ret, im_frame = cap.read()
        cv2.imshow("frame", im_frame)  # 显示圖像

        # im_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 可選擇轉換為灰度圖
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cv2.destroyAllWindows()
    return im_frame

im_frame = try_frame()
env.imshow(im_frame)

ps: 鏡頭角度會存在一定的歪斜,沒有關係,我們後面會進行處理。

2. 圖像預處理:獲取屏幕ROI

利用屏幕的亮度,通過簡單的閾值操作和輪廓操作,獲取屏幕輪廓,然後將圖像角度校正,最後獲得正向的文字內容。

2.1. 分離提取屏幕區域

通過OTSU的閾值化操作,將圖像處理為二值狀態。這個很重要,因為如果直接使用彩圖或灰度圖,會由於外部光線的變化,導致後期字符匹配時整體灰度值與模板的差別而降低置信度,導致較大的誤差。而二值圖可以避免這個問題。

然後利用開運算(白底黑字,如果黑底白字則為閉運算),消除噪點。

im_latest = try_frame()
im_gray = mvlib.color.rgb2gray(image)
im_bin = mvlib.filters.threshold(im_gray, invert=False)
# im_erosion = mvlib.morphology.erosion(im_bin, (11, 11))
# im_dilation = mvlib.morphology.dilation(im_erosion, (5, 5))
im_opening = mvlib.morphology.opening(im_bin, (11, 11))
env.imshow(im_opening)

2.2. 計算屏幕區域的旋轉角度

提取圖像的最大輪廓,然後獲取其包絡矩形。

list_cnts = mvlib.contours.find_cnts(im_opening)
if len(list_cnts) != 1:
    print(f"非唯一輪廓,請通過面積篩選過濾")
    # assert 0
    cnts_sorted = mvlib.contours.cnts_sort(list_cnts, mvlib.contours.cnt_area)
    list_cnts = [cnts_sorted[0]]

box, results = mvlib.contours.approx_rect(list_cnts[0], True)
angle = results[2]  # 此處的角度是向逆時針傾斜,記作:-4
if abs(angle) > 45:
    angle = (angle + 45) % 90 - 45
print(angle, box)

上述過程輸出:

1.432098388671875
[[282 173]
 [ 29 167]
 [ 32  41]
 [285  47]]

2.3. 裁剪屏幕區域

至此可以丟棄im_opening以及im_bin的圖像了。我們重新回到im_gray上進行操作(需要重新進行閾值化以獲取文字的二值圖)。

list_width = box[:,0]
list_height= box[:,1]
w_min, w_max = min(list_width), max(list_width)
h_min, h_max = min(list_height), max(list_height)

im_screen = im_gray[h_min:h_max, w_min:w_max]
env.imshow(im_screen)

2.4. 旋轉圖像至正向視角

im_screen_orthogonal = mvlib.transform.rotate(im_screen, angle, False)
# env.imshow(im_screen_orthogonal)
im_screen_core = im_screen_orthogonal[20:-20, 20:-20]
env.imshow(im_screen_core)

2.5. 提取文字圖像

第二次執行閾值化操作,但這一次是在屏幕內部,排除了屏幕外複雜的背景后,可以很容易的獲取到文字的內容。由於我們只關心数字,所以通過閉運算將細體字過濾掉。

im_core_bin = mvlib.filters.threshold(im_screen_core, invert=False)
im_closing = mvlib.morphology.closing(im_core_bin, (3,3))
env.imshow(im_closing)

2.6. 封裝上述過程

瑣碎的預處理過程就告一段落了,我們可以將上述的內容封裝成一個簡單的函數:

def preprocess():
    # 獲取屏幕區域
    im_latest = try_frame()
    ...
    im_closing = mvlib.morphology.closing(im_core_bin, (3,3))
    return im_closing

3. 字符分割,獲取單個字符的圖像

字符分割,一方面是製作模板的需要(當然,你也可以直接用畫圖工具裁剪出一張模板圖像);另一方面是為了加速模板匹配的效率。當然,你完全可以在整張圖像上利用 match_template() 查找模板,但如果進行多模板匹配,重複的掃描整張圖像,效率就大打折扣了。

先提供完整的代碼

char_width_min = 7
gap_height_max = 5

def segment_chars(im_core):
    list_char_img = []
    # 字符區域
    raw_bkg = np.all(im_core, axis=0)
    col_bkg = np.all(im_core, axis=1)

    # 計算字高
    ndarr_char_height = np.where(False == col_bkg)[0]
    char_height_start = ndarr_char_height[0]
    item_last = ndarr_char_height[0]
    for item in ndarr_char_height:
        if item - item_last > gap_height_max:
            char_height_start = item
        item_last = item
    char_height_end = ndarr_char_height[-1] +1
    print(f"字高【{char_height_end - char_height_start}】")

    ndarr_chars_pos = np.where(False == raw_bkg)[0]
    ndarr_chars_pos = np.append(ndarr_chars_pos,
                                im_core.shape[1] + char_width_min)

    last_idx = ndarr_chars_pos[0]
    curr_char_width = 1
    for curr_idx in ndarr_chars_pos:
        idx_diff = curr_idx - last_idx
        # 這裏應該限制最小寬度>=2,否則認為是一個粘連字
        if idx_diff <= 2:
            curr_char_width += idx_diff
        else:  # 新的字符
            char_width_end = last_idx +1
            char_width_start = char_width_end - curr_char_width
            im_char_last = im_core[char_height_start:char_height_end,
                                char_width_start:char_width_end]
            list_char_img.append(im_char_last)
            curr_char_width = 0
        last_idx = curr_idx
    return list_char_img

按照行列,獲取圖像中的文字像素點集:

raw_bkg = np.all(im_core, axis=0)
col_bkg = np.all(im_core, axis=1)

由此,可以知道255(黑色)的區域從大約 39 到 75,那麼 75 - 29 = 36 就是字高。

另外,圖像中有可能存在噪點,去掉就是了(我這裏只是簡單粗暴的處理下,請見諒)。

行的處理同樣。如果發現間隔,那麼就可以分離字符。最後,輸出每個字符的圖像。

檢驗下效果:

list_char_imgs = segment_chars(im_core)
env.imshow(list_char_imgs[1])

4. 模板匹配:確定字符內容

利用模板匹配,實現字符識別的過程。這裏不再細說OpenCV的 cv2.matchTemplate() 函數,只描述應用過程。

4.1. make_template

首先,有必要把字符先作為模板存儲下來。

def make_tpls(list_tpl_imgs, dir_save, dict_tpl=None):
    if not dict_tpl:
        dict_tpl = {}

    str_items = input("請輸入模板上的文本內容,用於校對(例如215801): ")

    assert len(str_items) == len(list_tpl_imgs)
    for i, v in enumerate(str_items):
        filename = v
        if v in dict_tpl:
            filename = v + "_" + str(random.random())
        else:
            dict_tpl[v] = list_tpl_imgs[i]
        path_save = os.path.join(dir_save, filename + ".jpg")
        mvlib.io.imsave(path_save, list_tpl_imgs[i])

    return dict_tpl

這裏,同一字符有必要多存儲幾張,最後擇優(或者一個字符通過多個模板匹配的結果來確定)。

4.2. 模板修復

這個過程,雖然沒啥子技術含量,但卻對結果影響很大。在前一步驟中,我們每一個字符都收集了多張模板圖像。現在,從中擇優錄取。還有,可以手動編輯模板的圖片,去除模板多餘的白邊(邊並不是文字內容的一部分,而且會降低字符的匹配度)。

4.3. 重新加載模板數據

def load_saved_tpls(dir_tpl):
    saved_tpls = os.listdir(dir_tpl)

    dict_tpl = {}  # {"1": imread("mvdev/tmp/tpl/1.jpg"), ...}
    for i in saved_tpls:
        filename = os.path.splitext(i)[0]
        path_tpl = os.path.join(dir_tpl, i)

        im_rgb = cv2.imread(path_tpl)
        im_gray = mvlib.color.rgb2gray(im_rgb)
        dict_tpl[filename] = im_gray
    return dict_tpl

dir_tpl = "tpl/"
dict_tpls = load_saved_tpls(dir_tpl)

4.4. 模板匹配

def number_ocr_matching(im_char):
    most_likely = [1, ""]
    for key, im_tpl in dict_tpls.items():
        try:
            pos, similarity = mvlib.feature.match_template(im_char, im_tpl, way="most")
            if similarity < most_likely[0]:
                most_likely = [similarity, key]
        except:
            im_char_old = im_char.copy()
            h = max(im_char.shape[0], im_tpl.shape[0])
            w = max(im_char.shape[1], im_tpl.shape[1])
            im_char = np.ones((h,w), dtype="uint8") * 255
            # im_char2 = mvlib.pixel.bitwise_and(z, im_char)
            im_char[:im_char_old.shape[0], :im_char_old.shape[1]] = im_char_old

            pos, similarity = mvlib.feature.match_template(im_char, im_tpl, way="most")
            if similarity < most_likely[0]:
                most_likely = [similarity, key]

    print(f"字符識別為【{most_likely[1]}】相似度【{most_likely[0]}】")
    return most_likely[1]

def application(list_char_imgs):
    str_ocr = ""
    for im_char in list_char_imgs:
        width_img = im_char.shape[1]
        # 判斷字符
        match_char = number_ocr_matching(im_char)
        str_ocr += match_char
    return str_ocr

str_ocr2 = application(list_char_imgs)
print(str_ocr2)

過程中,opencv出現了報錯,是由於模板的shape大於當前分割字符的shape。這個很正常,採集圖像時由於距離的微調(注意,距離變化不能太大,OpenCV的默認算子不支持模板縮放)可能導致字符尺寸更小。解決方案也很簡單,直接把字符圖像拓展到大於模板的狀態就OK了。

額,忘了刪除debug信息了……再來一次~

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

8分之1的歐洲人口死於環境污染 空污、噪音通通上榜

摘錄自2020年9月15日自由時報報導

根據歐洲環境署的一項調查研究報告,歐盟人口大約有8分之1的死與環境污染有關;對此,歐洲環境署負責人建議,優先保護社會上最受威脅的族群,解決貧困問題。

歐洲環境署補充,化學物質、過量使用抗生素後對病原體造成的抗藥性以及被污染的飲用水,上述也是導致人們過早死亡的因素,而在許多東歐國家,環境因素導致的過早死亡率比西歐高得多。

根據世衛組織的數據,歐盟國家過早死亡的比例大約為13%,相當於每年有63萬人過早死亡,不幸的是,環境因素(例如:癌症、心臟病和中風)造成的死亡原本是可以避免。

歐洲環境署負責人漢斯.布魯尼克斯(Hans Bruyninckx)建議,必須採取措施來保護社會上最受威脅的族群,而貧困通常是主要問題,因為它會帶來惡劣的環境和影響健康狀況,因此為來歐洲未來可以在此多著墨,如此一來才能真正解決環境與健康的問題。

污染治理
國際新聞
歐洲
空污
噪音

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

除了思域,這3款10來萬的轎車也能讓你爽到停不下來

但速度上去之後還是很有感覺的,特別是當你跑高速時,沉穩的底盤精準的轉向能給予你足夠的信心,可能不經意間你的時速就上百了,如果你覺得普通版的高爾夫不夠過癮,那就上GTI或R-Line吧,畢竟小鋼炮是不會浪得虛名的。說到這可能很多朋友糊塗了,操控都是它們的主旋律,那到底要選哪款呀。

最近不少網友諮詢想要一輛具有駕駛樂趣的緊湊型轎車該買哪款好,小雅腦中第一個冒出來的當然是思域啦,但是仔細想想思域太火了、等車實在太煎熬,所以今天我推薦另外三款,快來看看有沒有對你口味的:

一、外觀與內飾

如果你說思域是日繫緊湊型轎車的顏值擔當,馬自達車主可要表示不服了,瞧瞧這輛昂克賽拉,我保證在車流中你能一眼就找出來,魂動設計賦予了它獨特的韻律美,盾型進氣格柵、翼型鍍鉻飾條、犀利的前大燈、偏長的引擎蓋、再加上動感的線條,說不驚艷那還真是騙人的。

第二個要介紹的是福克斯,它有着一張略顯囂張的前臉,獠牙狀進氣格柵顯露出十足的攻擊性,鷹眼大燈看上去炯炯有神,車身線條力量感十足,果然很有運動氣息。

相比之下,小雅覺得高爾夫看起來要低調很多,沒有昂克賽拉那嫵媚多姿的車身線條,也沒有福克斯那搶眼的馬丁臉,可偏偏是這樣的大眾家族式設計風格依舊能討得不少人的喜愛,畢竟每個人的審美不一樣。

我們接着來看內飾:

昂克賽拉與福克斯的用料都中規中矩,不過昂克賽拉的中控面板上按鍵比較少,看起來十分簡潔,並且懸浮式的中控显示屏提升不少檔次感。福克斯的中控台佔用空間較多,讓我覺得有點壓迫感,並且做工要粗糙一些。

高爾夫的內飾設計是三車中最有質感的,雖然看起來並沒什麼新鮮味道,但它摸起來軟、做工細緻,而且中控面板的設計整體偏向駕駛席一側,方便駕駛員在行車時進行操作。

二、駕駛感受

關於造型設計就先說到這了,畢竟我們今天的主題是駕駛樂趣 ,那麼三者中誰的駕控最好呢?

昂克賽拉最大的優點主要有兩個,首先自然吸氣發動機動力輸出很線性,變速箱降擋平順,還有一點是轉向特別靈敏。雖然小雅覺得人車合一這個口號略顯誇張,但不可否認它開起來確實很靈活輕快。

對了,補充一點,昂克賽拉還加上了GVC扭矩分配系統,用於改善過彎時車輛的動態表現,集這麼多亮點於一身,我想這也是廣大車迷朋友們喜歡它的主要原因。

再來看看福克斯,這位運動健將近年來慢慢朝舒適性方向有所靠攏了。以前的福克斯動力很猛,還可謂是指哪打哪,但現在略偏舒適的調校讓它變得不那麼純粹了。

但它依舊是這個級別裏面不可忽視的,它的1.5T發動機功率在同排量渦輪增壓發動機中最出色的,最大馬力高達181匹,儘管油耗有點讓人心疼,但是它加速暢快啊。總的來說儘管整體質量口碑一般,但這並不影響年輕人將其作為人生第一部車的首選。

很多高爾夫車主被稱為“神車黨”,不過你要知道高爾夫有很多種,分為普通版、R-Line、GTI,動力的選擇也是多種多樣,其中的1.4T發動機匹配7擋雙離合變速箱可以說是黃金組合了,變速箱換擋快,動力的話初段加速不會太給力,需要你踩深一點油門。

但速度上去之後還是很有感覺的,特別是當你跑高速時,沉穩的底盤精準的轉向能給予你足夠的信心,可能不經意間你的時速就上百了,如果你覺得普通版的高爾夫不夠過癮,那就上GTI或R-Line吧,畢竟小鋼炮是不會浪得虛名的。

說到這可能很多朋友糊塗了,操控都是它們的主旋律,那到底要選哪款呀!別急,我們接着來看它們的配置:

三、裝備率

1、福克斯全系標配前後排頭部氣囊/氣簾,氣囊的重要性想必大家也都知道,所以說福克斯這點做的很厚道,而高爾夫要在指導價為14.49萬的2018款 1.6L 自動舒適型上才開始配備,昂克賽拉就更讓小雅失望了,只有頂配車型才配備有。

2、福克斯與昂克賽拉的頂配車型帶有主動安全系統,高爾夫全系沒有這一配置,而是多出疲勞駕駛提示功能,但小雅覺得有點華而不實。

3、再來看看倒車視頻影像,福克斯又給我了驚喜,做到了全系標配,昂克賽拉要在指導價為12.89萬的2017款 三廂 1.5L 手動豪華型才開始配備,而2018款的高爾夫只有GTI與280TSI 自動旗艦型上才帶有。

4、在燈光配置方面,昂克賽拉的LED大燈普及率高,在12.89萬的2017款 三廂 1.5L 手動豪華型上便可獲得,高爾夫要在15.79萬的2018款 280TSI 手動R-Line型才能買到,福克斯則全系都找不到LED大燈的影子。

5、另外,昂克賽拉全系標配多功能方向盤,福克斯全系標配8英寸中控屏,高爾夫全系支持全車車窗一鍵升降。

小雅覺得三車中福克斯的價格不算高,但配置的普及率卻非常高,再結合上面的表現來看是三車中性價比最高的。

四、結語

當然車無完車,三者最大的不足是空間都不太理想,畢竟這不是它們主攻的方面,另外高爾夫的價格比較高,特別是售價高達20多萬的GTI令不少人望而卻步。

但不管怎樣,手握住它們三中間任何一輛的方向盤,你都會忍不住多跑一會,難道不是嗎?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

3dTiles 數據規範詳解[1] 介紹

版權:轉載請帶原地址。https://www.cnblogs.com/onsummer/p/12799366.html @秋意正寒

Web中的三維

html5和webgl技術使得瀏覽器三維變成了可能。

巧婦難為無米之炊,三維數據(三維模型)是三維可視化重要的一環,事實上就是:三維數據眾多,行業跨界廣。

參考資料:http://www.bgteach.com/article/132

three.js的各種加載器實現了大部分通用三維格式的加載,屏蔽了格式不同的數據結構差異。

然而,這樣還是不能滿足日益增長的效果需求,比如場景一大,模型文件體積變大,解析所耗費的時間越來越長。

webgl,包括所有gpu有關的圖形渲染編程,幾乎只認這樣的三維數據:頂點、頂點顏色、頂點法線、着色語言…

所以,三維圖形界的通用格式:glTF應運而生,它面向終點,它按照圖形編程所需的格式來存儲數據,藉以二進制編碼提高傳輸速度。

它不再使用面向對象的思維存儲三維模型、貼圖紋理,而是按顯卡的思維存儲,存的是頂點、法線、頂點顏色等最基礎的信息,只不過組織結構上進行了精心的設計。

它面向終點,就意味着可編輯性差,因為渲染性能的提高犧牲了可編輯性,它不再像3ds、dae甚至是max、skp一樣容易編輯和轉換。

事實上,大多數三維軟件提供了glTF格式的轉換,或多一步,或一步到位。

地理真三維

早年,地理的三維還處於地形三維上,即数字高程模型(DEM)提供地表的高度拉伸。柵格高程數據、等高線、不規則三角網等均是数字高程模型的具體案例。
下圖是不規則三角網,也即所謂的三角面片(圖形渲染中很常見):

隨着學科的融合、計算機技術和硬件的更新換代,使得有模型、有細節的真三維融入到GIS中成為了可能,或者說,計算機技術和硬件的升級,給GIS以更廣闊的視角觀察世界。

cesium.js 號稱是 webgl 封裝的三維地理庫,是支持 gltf 模型的加載的。

面對大規模精細三維數據的加載,還要照顧到GIS的各種坐標系統、分析計算,gltf這種單個模型的方案顯得力不從心。

2016年,Cesium 團隊借鑒傳統2DGIS的地圖規範——WMTS,借鑒圖形學中的層次細節模型,打造出大規模的三維數據標準—— 3d-Tiles,中文譯名:三維瓦片。

它在模型上利用了 gltf 渲染快的特點,對大規模的三維數據進行組織,包括層次細節模型、模型的屬性數據、模型的層級數據等。

3dTiles的設計思想

3dTiles 繼承了 gltf 的優點:貼合圖形渲染 API 的邏輯,討 GPU 喜愛,webgl 對其內部組織起來的三維模型數據,不需要轉換,可以直接渲染(glTF 的功勞)。

關於 glTF 是如何嵌入到 3dTiles 中的,開篇不談,後續精講。

我們區分一組概念:規範和實現。

3dTiles 是一種規範,在規範的指導下,各種資源文件可以是獨立存在於硬盤中的目錄、文件,也可以以二進制形式寫入數據庫中。目前,3dTiles 的官方實現只有 “散列文件”,也就是文件、文件夾的形式存儲在硬盤中,有關如何存儲到數據庫中的討論,官方仍在進行中(截至發博客)。

glTF 也是一種規範,它的數據文件不一定就是後綴名為 .gltf 的文件,也不一定只有一個文件(glTF 的文件還可以是二進制文件、紋理貼圖文件等,扯遠了哈)。
在本文,會嚴格指明是數據還是數據標準,如果我說的是 “XXX文件(例如 Bird.glb 文件)” ,那就是在指特定的文件。

3dTiles還有一個特點:那就是不記錄模型數據,只記錄各級“Tile”的邏輯關係,以及“Tile”自己的屬性信息。所謂的模型數據,是指三維模型的頂點、貼圖材質、法線、顏色等信息。邏輯關係是指,各級Tile是如何在空間中保持連續的,LOD是如何組織的。屬性信息就很簡單啦,門有門的生產商,窗戶有窗戶的使用年限等,往大了說,建築還有它自己的壽命、法人、施工單位等屬性信息。

3dTiles的特點總結如下:

  • 三維模型使用了 glTF 規範,繼承它的渲染高性能
  • 除了嵌入的 glTF,3dTiles 自己 只記錄各級Tile的空間邏輯關係(如何構成整個3dtiles)和屬性信息,以及模型與屬性如何掛接在一起的信息

我覺得你還是雲里霧裡的,下一節將展示3dTiles具體數據,說說3dTiles的組織結構,說說3dTiles中的”Tile”,也就是“三維瓦片數據”中的“瓦片”是什麼。

3dTiles系列博客最終目錄:

01 引入與博客目錄:3dTiles 數據規範詳解

02 Tileset與Tile

03 內嵌在瓦片文件中的兩大數據表

04.1 B3dm 類型

04.2 I3dm 類型

04.3 Pnts 類型

04.4 Cmpt 類型

04.5 未發布的瓦片規範

05 3dTiles強大的擴展能力

06 優缺點

07 與I3S比較

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

【其他文章推薦】

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

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

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

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

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

分類
發燒車訊

為疫苗研發犧牲? 保育團體憂:25萬尾鯊魚恐間接受害

摘錄自2020年9月29日自由時報報導

為盡速結束武漢肺炎(COVID-19)疫情所帶來的災難,各國無不卯足全力研發疫苗,然而近期有研發廠商為了讓疫苗的效果穩定,決定在疫苗內添加高效的醫學物質「鯊烯」(Squalene),然而鯊烯這種物質相當稀少,美國有鯊魚保育團體推估,光是製造提供給美國使用的疫苗量,恐就要殺死超過2.1萬條鯊魚,若是全世界範圍,「可能要殺害25萬條鯊魚」。

綜合外媒報導,「鯊烯」主要從鯊魚的肝油中提煉而出,在醫學與美容方面都是極為重要的高效素質,不僅可以滋潤皮膚,也可以提高、增強免疫力,加在疫苗中可使疫苗的效力提升,然而鯊魚肝油中提煉出的鯊烯十分稀少,平均一噸的鯊烯大約需要3000條鯊魚。

英國製藥大廠葛蘭素史克(GlaxoSmithKline)專門生產用於流感疫苗中的以鯊烯製成的佐劑,而葛蘭素史克曾表示,將在2021年生產10億個以鯊烯製成的「武漢肺炎疫苗用佐劑」,引起保育團體的憂慮;位在美國加州的鯊魚保育團體鯊魚同盟(Shark Allies)表示,如果全世界的人都會接種這種加入佐劑的疫苗,「那可能要殺害25萬條鯊魚」,如果再算上二次接種,數量還會翻倍到50萬條。

海洋
國際新聞
鯊魚

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

【其他文章推薦】

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

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

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

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

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

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

分類
發燒車訊

Openshift 4.4 靜態 IP 離線安裝系列:初始安裝

上篇文章準備了離線安裝 OCP 所需要的離線資源,包括安裝鏡像、所有樣例 Image StreamOperatorHub 中的所有 RedHat Operators。本文就開始正式安裝 OCP(Openshift Container Platform) 集群,包括 DNS 解析、負載均衡配置、ignition 配置文件生成和集群部署。

OCP 安裝期間需要用到多個文件:安裝配置文件、Kubernetes 部署清單、Ignition 配置文件(包含了 machine types)。安裝配置文件將被轉換為 Kubernetes 部署清單,然後將清單包裝到 Ignition 配置文件中。 安裝程序使用這些 Ignition 配置文件來創建 Openshift 集群。運行安裝程序時,所有原始安裝配置文件都會修改,因此在安裝之前應該先備份文件。

1. 安裝過程

在安裝 OCP 時,我們需要有一台引導主機(Bootstrap)。這個主機可以訪問所有的 OCP 節點。引導主機啟動一個臨時控制平面,它啟動 OCP 集群的其餘部分然後被銷毀。引導主機使用 Ignition 配置文件進行集群安裝引導,該文件描述了如何創建 OCP 集群。安裝程序生成的 Ignition 配置文件包含 24 小時後過期的證書,所以必須在證書過期之前完成集群安裝。

引導集群安裝包括如下步驟:

  • 引導主機啟動並開始託管 Master 節點啟動所需的資源。
  • Master 節點從引導主機遠程獲取資源並完成引導。
  • Master 節點通過引導主機構建 Etcd 集群。
  • 引導主機使用新的 Etcd 集群啟動臨時 Kubernetes 控制平面。
  • 臨時控制平面在 Master 節點啟動生成控制平面。
  • 臨時控制平面關閉並將控制權傳遞給生產控制平面。
  • 引導主機將 OCP 組件注入生成控制平面。
  • 安裝程序關閉引導主機。

引導安裝過程完成以後,OCP 集群部署完畢。然後集群開始下載並配置日常操作所需的其餘組件,包括創建計算節點、通過 Operator 安裝其他服務等。

2. 準備服務器資源

服務器規劃如下:

  • 三個控制平面節點,安裝 Etcd、控制平面組件和 Infras 基礎組件。
  • 兩個計算節點,運行實際負載。
  • 一個引導主機,執行安裝任務,集群部署完成后可刪除。
  • 一個基礎節點,用於準備上節提到的離線資源,同時用來部署 DNS 和負載均衡。
  • 一個鏡像節點,用來部署私有鏡像倉庫 Quay
主機類型 操作系統 Hostname vCPU 內存 存儲 IP FQDN
鏡像節點 RHEL 7.6 registry 4 8GB 150GB 192.168.57.70 registry.openshift4.example.com
基礎節點 RHEL 7.6 bastion 4 16GB 120GB 192.168.57.60 bastion.openshift4.example.com
引導主機 RHCOS bootstrap 4 16GB 120GB 192.168.57.61 bootstrap.openshift4.example.com
控制平面 RHCOS master1 4 16GB 120GB 192.168.57.62 master1.openshift4.example.com
控制平面 RHCOS master2 4 16GB 120GB 192.168.57.63 master2.openshift4.example.com
控制平面 RHCOS master3 4 16GB 120GB 192.168.57.64 master3.openshift4.example.com
計算節點 RHCOS 或 RHEL 7.6 worker1 2 8GB 120GB 192.168.57.65 worker1.openshift4.example.com
計算節點 RHCOS 或 RHEL 7.6 worker2 2 8GB 120GB 192.168.57.66 worke2.openshift4.example.com

3. 防火牆配置

接下來看一下每個節點的端口號分配。

所有節點(計算節點和控制平面)之間需要開放的端口:

協議 端口 作用
ICMP N/A 測試網絡連通性
TCP 9000-9999 節點的服務端口,包括 node exporter 使用的 9100-9101 端口和 Cluster Version Operator 使用的 9099 端口
1025010259 Kubernetes 預留的默認端口
10256 openshift-sdn
UDP 4789 VXLAN 協議或 GENEVE 協議的通信端口
6081 VXLAN 協議或 GENEVE 協議的通信端口
90009999 節點的服務端口,包括 node exporter 使用的 9100-9101 端口
3000032767 Kubernetes NodePort

控制平面需要向其他節點開放的端口:

協議 端口 作用
TCP 23792380 Etcd 服務端口
6443 Kubernetes API

除此之外,還要配置兩個四層負載均衡器,一個用來暴露集群 API,一個用來暴露 Ingress:

端口 作用 內部 外部 描述
6443 引導主機和控制平面使用。在引導主機初始化集群控制平面后,需從負載均衡器中手動刪除引導主機 x x Kubernetes API server
22623 引導主機和控制平面使用。在引導主機初始化集群控制平面后,需從負載均衡器中手動刪除引導主機 x Machine Config server
443 Ingress Controller 或 Router 使用 x x HTTPS 流量
80 Ingress Controller 或 Router 使用 x x HTTP 流量

4. 配置 DNS

按照官方文檔,使用 UPI 基礎架構的 OCP 集群需要以下的 DNS 記錄。在每條記錄中,<cluster_name> 是集群名稱,<base_domain> 是在 install-config.yaml 文件中指定的集群基本域,如下錶所示:

組件 DNS記錄 描述
Kubernetes API api.<cluster_name>.<base_domain>. 此 DNS 記錄必須指向控制平面節點的負載均衡器。此記錄必須可由集群外部的客戶端和集群中的所有節點解析。
api-int.<cluster_name>.<base_domain>. 此 DNS 記錄必須指向控制平面節點的負載均衡器。此記錄必須可由集群外部的客戶端和集群中的所有節點解析。
Routes *.apps.<cluster_name>.<base_domain>. DNS 通配符記錄,指向負載均衡器。這個負載均衡器的後端是 Ingress router 所在的節點,默認是計算節點。此記錄必須可由集群外部的客戶端和集群中的所有節點解析。
etcd etcd-<index>.<cluster_name>.<base_domain>. OCP 要求每個 etcd 實例的 DNS 記錄指向運行實例的控制平面節點。etcd 實例由 值區分,它們以 0 開頭,以 n-1 結束,其中 n 是集群中控制平面節點的數量。集群中的所有節點必須都可以解析此記錄。
_etcd-server-ssl._tcp.<cluster_name>.<base_domain>. 因為 etcd 使用端口 2380 對外服務,因此需要建立對應每台 etcd 節點的 SRV DNS 記錄,優先級 0,權重 10 和端口 2380

DNS 服務的部署方法由很多種,我當然推薦使用 CoreDNS,畢竟雲原生標配。由於這裏需要添加 SRV 記錄,所以需要 CoreDNS 結合 etcd 插件使用。以下所有操作在基礎節點上執行。

首先通過 yum 安裝並啟動 etcd:

$ yum install -y etcd
$ systemctl enable etcd --now

然後下載 CoreDNS 二進制文件:

$ wget https://github.com/coredns/coredns/releases/download/v1.6.9/coredns_1.6.9_linux_amd64.tgz
$ tar zxvf coredns_1.6.9_linux_amd64.tgz
$ mv coredns /usr/local/bin

創建 Systemd Unit 文件:

$ cat > /etc/systemd/system/coredns.service <<EOF
[Unit]
Description=CoreDNS DNS server
Documentation=https://coredns.io
After=network.target

[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
LimitNPROC=512
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
User=coredns
WorkingDirectory=~
ExecStart=/usr/local/bin/coredns -conf=/etc/coredns/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

新建 coredns 用戶:

$ useradd coredns -s /sbin/nologin

新建 CoreDNS 配置文件:

$ cat > /etc/coredns/Corefile <<EOF
.:53 {  # 監聽 TCP 和 UDP 的 53 端口
    template IN A apps.openshift4.example.com {
    match .*apps\.openshift4\.example\.com # 匹配請求 DNS 名稱的正則表達式
    answer "{{ .Name }} 60 IN A 192.168.57.60" # DNS 應答
    fallthrough
    }
    etcd {   # 配置啟用 etcd 插件,後面可以指定域名,例如 etcd test.com {
        path /skydns # etcd 裏面的路徑 默認為 /skydns,以後所有的 dns 記錄都存儲在該路徑下
        endpoint http://localhost:2379 # etcd 訪問地址,多個空格分開
        fallthrough # 如果區域匹配但不能生成記錄,則將請求傳遞給下一個插件
        # tls CERT KEY CACERT # 可選參數,etcd 認證證書設置
    }
    prometheus  # 監控插件
    cache 160
    loadbalance   # 負載均衡,開啟 DNS 記錄輪詢策略
    forward . 192.168.57.1
    log # 打印日誌
}
EOF

其中 template 插件用來實現泛域名解析。

啟動 CoreDNS 並設置開機自啟:

$ systemctl enable coredns --now

驗證泛域名解析:

$ dig +short apps.openshift4.example.com @127.0.0.1
192.168.57.60

$ dig +short x.apps.openshift4.example.com @127.0.0.1
192.168.57.60

添加其餘 DNS 記錄:

$ alias etcdctlv3='ETCDCTL_API=3 etcdctl'
$ etcdctlv3 put /skydns/com/example/openshift4/api '{"host":"192.168.57.60","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/api-int '{"host":"192.168.57.60","ttl":60}'

$ etcdctlv3 put /skydns/com/example/openshift4/etcd-0 '{"host":"192.168.57.62","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/etcd-1 '{"host":"192.168.57.63","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/etcd-2 '{"host":"192.168.57.64","ttl":60}'

$ etcdctlv3 put /skydns/com/example/openshift4/_tcp/_etcd-server-ssl/x1 '{"host":"etcd-0.openshift4.example.com","ttl":60,"priority":0,"weight":10,"port":2380}'
$ etcdctlv3 put /skydns/com/example/openshift4/_tcp/_etcd-server-ssl/x2 '{"host":"etcd-1.openshift4.example.com","ttl":60,"priority":0,"weight":10,"port":2380}'
$ etcdctlv3 put /skydns/com/example/openshift4/_tcp/_etcd-server-ssl/x3 '{"host":"etcd-2.openshift4.example.com","ttl":60,"priority":0,"weight":10,"port":2380}'

# 除此之外再添加各節點主機名記錄
$ etcdctlv3 put /skydns/com/example/openshift4/bootstrap '{"host":"192.168.57.61","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/master1 '{"host":"192.168.57.62","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/master2 '{"host":"192.168.57.63","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/master3 '{"host":"192.168.57.64","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/worker1 '{"host":"192.168.57.65","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/worker2 '{"host":"192.168.57.66","ttl":60}'
$ etcdctlv3 put /skydns/com/example/openshift4/registry '{"host":"192.168.57.70","ttl":60}'

驗證 DNS 解析:

$ yum install -y bind-utils
$ dig +short api.openshift4.example.com @127.0.0.1
192.168.57.60

$ dig +short api-int.openshift4.example.com @127.0.0.1
192.168.57.60

$ dig +short etcd-0.openshift4.example.com @127.0.0.1
192.168.57.62
$ dig +short etcd-1.openshift4.example.com @127.0.0.1
192.168.57.63
$ dig +short etcd-2.openshift4.example.com @127.0.0.1
192.168.57.64

$ dig +short -t SRV _etcd-server-ssl._tcp.openshift4.example.com @127.0.0.1
10 33 2380 etcd-0.openshift4.example.com.
10 33 2380 etcd-1.openshift4.example.com.
10 33 2380 etcd-2.openshift4.example.com.

$ dig +short bootstrap.openshift4.example.com @127.0.0.1
192.168.57.61
$ dig +short master1.openshift4.example.com @127.0.0.1
192.168.57.62
$ dig +short master2.openshift4.example.com @127.0.0.1
192.168.57.63
$ dig +short master3.openshift4.example.com @127.0.0.1
192.168.57.64
$ dig +short worker1.openshift4.example.com @127.0.0.1
192.168.57.65
$ dig +short worker2.openshift4.example.com @127.0.0.1
192.168.57.66

5. 配置負載均衡

負載均衡我選擇使用 Envoy,先準備配置文件:

Bootstrap

# /etc/envoy/envoy.yaml
node:
  id: node0
  cluster: cluster0
dynamic_resources:
  lds_config:
    path: /etc/envoy/lds.yaml
  cds_config:
    path: /etc/envoy/cds.yaml
admin:
  access_log_path: "/dev/stdout"
  address:
    socket_address:
      address: "0.0.0.0"
      port_value: 15001

LDS

# /etc/envoy/lds.yaml
version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
  name: listener_openshift-api-server
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 6443
  filter_chains:
  - filters:
    - name: envoy.tcp_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        stat_prefix: openshift-api-server
        cluster: openshift-api-server
        access_log:
          name: envoy.access_loggers.file
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: /dev/stdout
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
  name: listener_machine-config-server
  address:
    socket_address:
      address: "::"
      ipv4_compat: true
      port_value: 22623
  filter_chains:
  - filters:
    - name: envoy.tcp_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        stat_prefix: machine-config-server
        cluster: machine-config-server
        access_log:
          name: envoy.access_loggers.file
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: /dev/stdout
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
  name: listener_ingress-http
  address:
    socket_address:
      address: "::"
      ipv4_compat: true
      port_value: 80
  filter_chains:
  - filters:
    - name: envoy.tcp_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        stat_prefix: ingress-http
        cluster: ingress-http
        access_log:
          name: envoy.access_loggers.file
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: /dev/stdout
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
  name: listener_ingress-https
  address:
    socket_address:
      address: "::"
      ipv4_compat: true
      port_value: 443
  filter_chains:
  - filters:
    - name: envoy.tcp_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        stat_prefix: ingress-https
        cluster: ingress-https
        access_log:
          name: envoy.access_loggers.file
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            path: /dev/stdout

CDS

# /etc/envoy/cds.yaml
version_info: "0"
resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  name: openshift-api-server
  connect_timeout: 1s
  type: strict_dns
  dns_lookup_family: V4_ONLY
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: openshift-api-server
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.61
              port_value: 6443
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.62
              port_value: 6443
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.63
              port_value: 6443
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.64
              port_value: 6443
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  name: machine-config-server
  connect_timeout: 1s
  type: strict_dns
  dns_lookup_family: V4_ONLY
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: machine-config-server
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.61
              port_value: 22623
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.62
              port_value: 22623
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.63
              port_value: 22623
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.64
              port_value: 22623
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  name: ingress-http
  connect_timeout: 1s
  type: strict_dns
  dns_lookup_family: V4_ONLY
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: ingress-http
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.65
              port_value: 80
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.66
              port_value: 80
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  name: ingress-https
  connect_timeout: 1s
  type: strict_dns
  dns_lookup_family: V4_ONLY
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: ingress-https
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.65
              port_value: 443
      - endpoint:
          address:
            socket_address:
              address: 192.168.57.66
              port_value: 443

配置看不懂的去看我的电子書:Envoy 中文指南

啟動 Envoy

$ podman run -d --restart=always --name envoy --net host -v /etc/envoy:/etc/envoy envoyproxy/envoy

6. 安裝準備

生成 SSH 私鑰並將其添加到 agent

在安裝過程中,我們會在基礎節點上執行 OCP 安裝調試和災難恢復,因此必須在基礎節點上配置 SSH key,ssh-agent 將會用它來執行安裝程序。

基礎節點上的 core 用戶可以使用該私鑰登錄到 Master 節點。部署集群時,該私鑰會被添加到 core 用戶的 ~/.ssh/authorized_keys 列表中。

密鑰創建步驟如下:

① 創建無密碼驗證的 SSH key:

$ ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/new_rsa

② 啟動 ssh-agent 進程作為後台任務:

$ eval "$(ssh-agent -s)"

③ 將 SSH 私鑰添加到 ssh-agent

$ ssh-add ~/.ssh/new_rsa

後續集群安裝過程中,有一步會提示輸入 SSH public key,屆時使用前面創建的公鑰 new_rsa.pub 就可以了。

獲取安裝程序

如果是在線安裝,還需要在基礎節點上下載安裝程序。但這裡是離線安裝,安裝程序在上篇文章中已經被提取出來了,所以不需要再下載。

創建安裝配置文件

首先創建一個安裝目錄,用來存儲安裝所需要的文件:

$ mkdir /ocpinstall

自定義 install-config.yaml 並將其保存在 /ocpinstall 目錄中。配置文件必須命名為 install-config.yaml。配置文件內容:

apiVersion: v1
baseDomain: example.com
compute:
- hyperthreading: Enabled
  name: worker
  replicas: 0
controlPlane:
  hyperthreading: Enabled
  name: master
  replicas: 3
metadata:
  name: openshift4
networking:
  clusterNetwork:
  - cidr: 10.128.0.0/14
    hostPrefix: 23
  networkType: OpenShiftSDN
  serviceNetwork:
  - 172.30.0.0/16
platform:
  none: {}
fips: false
pullSecret: '{"auths": ...}'
sshKey: 'ssh-rsa ...'
additionalTrustBundle: |
  -----BEGIN CERTIFICATE-----
  省略,注意這裏要前面空兩格
  -----END CERTIFICATE-----
imageContentSources:
- mirrors:
  - registry.openshift4.example.com/ocp4/openshift4
  source: quay.io/openshift-release-dev/ocp-release
- mirrors:
  - registry.openshift4.example.com/ocp4/openshift4
  source: quay.io/openshift-release-dev/ocp-v4.0-art-dev
  • baseDomain : 所有 Openshift 內部的 DNS 記錄必須是此基礎的子域,並包含集群名稱。
  • compute : 計算節點配置。這是一個數組,每一個元素必須以連字符 - 開頭。
  • hyperthreading : Enabled 表示啟用同步多線程或超線程。默認啟用同步多線程,可以提高機器內核的性能。如果要禁用,則控制平面和計算節點都要禁用。
  • compute.replicas : 計算節點數量。因為我們要手動創建計算節點,所以這裏要設置為 0。
  • controlPlane.replicas : 控制平面節點數量。控制平面節點數量必須和 etcd 節點數量一致,為了實現高可用,本文設置為 3。
  • metadata.name : 集群名稱。即前面 DNS 記錄中的 <cluster_name>
  • cidr : 定義了分配 Pod IP 的 IP 地址段,不能和物理網絡重疊。
  • hostPrefix : 分配給每個節點的子網前綴長度。例如,如果將 hostPrefix 設置為 23,則為每一個節點分配一個給定 cidr 的 /23 子網,允許 \(510 (2^{32 – 23} – 2)\) 個 Pod IP 地址。
  • serviceNetwork : Service IP 的地址池,只能設置一個。
  • pullSecret : 上篇文章使用的 pull secret,可通過命令 cat /root/pull-secret.json|jq -c 來壓縮成一行。
  • sshKey : 上面創建的公鑰,可通過命令 cat ~/.ssh/new_rsa.pub 查看。
  • additionalTrustBundle : 私有鏡像倉庫 Quay 的信任證書,可在鏡像節點上通過命令 cat /data/quay/config/ssl.cert 查看。
  • imageContentSources : 來自前面 oc adm release mirror 的輸出結果。

備份安裝配置文件,便於以後重複使用:

$ cd /ocpinstall
$ cp install-config.yaml  install-config.yaml.20200604

創建 Kubernetes 部署清單

創建 Kubernetes 部署清單后 install-config.yaml 將被刪除,請務必先備份此文件!

創建 Kubernetes 部署清單文件:

$ openshift-install create manifests --dir=/ocpinstall

修改 manifests/cluster-scheduler-02-config.yml 文件,將 mastersSchedulable 的值設為 flase,以防止 Pod 調度到控制節點。

創建 Ignition 配置文件

創建 Ignition 配置文件后 install-config.yaml 將被刪除,請務必先備份此文件!

$ cp install-config.yaml.20200604 install-config.yaml
$ openshift-install create ignition-configs --dir=/ocpinstall

生成的文件:

├── auth
│   ├── kubeadmin-password
│   └── kubeconfig
├── bootstrap.ign
├── master.ign
├── metadata.json
└── worker.ign

準備一個 HTTP 服務,這裏選擇使用 Nginx:

$ yum install -y nginx

修改 Nginx 的配置文件 /etc/nginx/nginx/.conf,將端口改為 8080(因為負載均衡器已經佔用了 80 端口)。然後啟動 Nginx 服務:

$ systemctl enable nginx --now

Ignition 配置文件拷貝到 HTTP 服務的 ignition 目錄:

$ mkdir /usr/share/nginx/html/ignition
$ cp -r *.ign /usr/share/nginx/html/ignition/

獲取 RHCOS 的 BIOS 文件

下載用於裸機安裝的 BIOS 文件,並上傳到 Nginx 的目錄:

$ mkdir /usr/share/nginx/html/install
$ wget https://mirror.openshift.com/pub/openshift-v4/dependencies/rhcos/4.4/latest/rhcos-4.4.3-x86_64-metal.x86_64.raw.gz -O /usr/share/nginx/html/install/rhcos-4.4.3-x86_64-metal.x86_64.raw.gz

獲取 RHCOS 的 ISO 文件

本地下載 RHCOS 的 ISO 文件:https://mirror.openshift.com/pub/openshift-v4/dependencies/rhcos/4.4/latest/rhcos-4.4.3-x86_64-installer.x86_64.iso,然後上傳到 vSphere。步驟如下:

① 首先登陸 vSphere,然後點擊『存儲』。

② 選擇一個『數據存儲』,然後在右邊的窗口中選擇『上載文件』。

③ 選擇剛剛下載的 ISO 文件,上傳到 ESXI 主機。

7. 安裝集群

Bootstrap

最後開始正式安裝集群,先創建 bootstrap 節點虛擬機,操作系統選擇『Red Hat Enterprise Linux 7 (64-Bit)』,並掛載之前上傳的 ISO,按照之前的表格設置 CPU 、內存和硬盤,打開電源,然後按照下面的步驟操作:

① 在 RHCOS Installer 安裝界面按 Tab 鍵進入引導參數配置選項。

② 在默認選項 coreos.inst = yes 之後添加(由於無法拷貝粘貼,請輸入仔細核對后再回車進行):

ip=192.168.57.61::192.168.57.1:255.255.255.0:bootstrap.openshift4.example.com:ens192:none nameserver=192.168.57.60 coreos.inst.install_dev=sda coreos.inst.image_url=http://192.168.57.60:8080/install/rhcos-4.4.3-x86_64-metal.x86_64.raw.gz coreos.inst.ignition_url=http://192.168.57.60:8080/ignition/bootstrap.ign 

其中 ip=... 的含義為 ip=$IPADDRESS::$DEFAULTGW:$NETMASK:$HOSTNAMEFQDN:$IFACE:none

如圖所示:

③ 如果安裝有問題會進入 emergency shell,檢查網絡、域名解析是否正常,如果正常一般是以上參數輸入有誤,reboot 退出 shell 回到第一步重新開始。

安裝成功后從基礎節點通過命令 ssh -i ~/.ssh/new_rsa core@192.168.57.61 登錄 bootstrap 節點,然後驗證:

  • 網絡配置是否符合自己的設定:
    • hostname
    • ip route
    • cat /etc/resolv.conf
  • 驗證是否成功啟動 bootstrap 相應服務:
    • podman ps 查看服務是否以容器方式運行
    • 使用 ss -tulnp 查看 6443 和 22623 端口是否啟用。

這裏簡單介紹一下 bootstrap 節點的啟動流程,它會先通過 podman 跑一些容器,然後在容器裏面啟動臨時控制平面,這個臨時控制平面是通過 CRIO 跑在容器里的,有點繞。。直接看命令:

$ podman ps -a --no-trunc --sort created --format "{{.Command}}"

start --tear-down-early=false --asset-dir=/assets --required-pods=openshift-kube-apiserver/kube-apiserver,openshift-kube-scheduler/openshift-kube-scheduler,openshift-kube-controller-manager/kube-controller-manager,openshift-cluster-version/cluster-version-operator
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
render --dest-dir=/assets/cco-bootstrap --cloud-credential-operator-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:244ab9d0fcf7315eb5c399bd3fa7c2e662cf23f87f625757b13f415d484621c3
bootstrap --etcd-ca=/assets/tls/etcd-ca-bundle.crt --etcd-metric-ca=/assets/tls/etcd-metric-ca-bundle.crt --root-ca=/assets/tls/root-ca.crt --kube-ca=/assets/tls/kube-apiserver-complete-client-ca-bundle.crt --config-file=/assets/manifests/cluster-config.yaml --dest-dir=/assets/mco-bootstrap --pull-secret=/assets/manifests/openshift-config-secret-pull-secret.yaml --etcd-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:aba3c59eb6d088d61b268f83b034230b3396ce67da4f6f6d49201e55efebc6b2 --kube-client-agent-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:8eb481214103d8e0b5fe982ffd682f838b969c8ff7d4f3ed4f83d4a444fb841b --machine-config-operator-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:31dfdca3584982ed5a82d3017322b7d65a491ab25080c427f3f07d9ce93c52e2 --machine-config-oscontent-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:b397960b7cc14c2e2603111b7385c6e8e4b0f683f9873cd9252a789175e5c4e1 --infra-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:d7862a735f492a18cb127742b5c2252281aa8f3bd92189176dd46ae9620ee68a --keepalived-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:a882a11b55b2fc41b538b59bf5db8e4cfc47c537890e4906fe6bf22f9da75575 --coredns-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:b25b8b2219e8c247c088af93e833c9ac390bc63459955e131d89b77c485d144d --mdns-publisher-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:dea1fcb456eae4aabdf5d2d5c537a968a2dafc3da52fe20e8d99a176fccaabce --haproxy-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:7064737dd9d0a43de7a87a094487ab4d7b9e666675c53cf4806d1c9279bd6c2e --baremetal-runtimecfg-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:715bc48eda04afc06827189883451958d8940ed8ab6dd491f602611fe98a6fba --cloud-config-file=/assets/manifests/cloud-provider-config.yaml --cluster-etcd-operator-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:9f7a02df3a5d91326d95e444e2e249f8205632ae986d6dccc7f007ec65c8af77
render --prefix=cluster-ingress- --output-dir=/assets/ingress-operator-manifests
/usr/bin/cluster-kube-scheduler-operator render --manifest-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:187b9d29fea1bde9f1785584b4a7bbf9a0b9f93e1323d92d138e61c861b6286c --asset-input-dir=/assets/tls --asset-output-dir=/assets/kube-scheduler-bootstrap --config-output-file=/assets/kube-scheduler-bootstrap/config
/usr/bin/cluster-kube-controller-manager-operator render --manifest-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:187b9d29fea1bde9f1785584b4a7bbf9a0b9f93e1323d92d138e61c861b6286c --asset-input-dir=/assets/tls --asset-output-dir=/assets/kube-controller-manager-bootstrap --config-output-file=/assets/kube-controller-manager-bootstrap/config --cluster-config-file=/assets/manifests/cluster-network-02-config.yml
/usr/bin/cluster-kube-apiserver-operator render --manifest-etcd-serving-ca=etcd-ca-bundle.crt --manifest-etcd-server-urls=https://localhost:2379 --manifest-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:187b9d29fea1bde9f1785584b4a7bbf9a0b9f93e1323d92d138e61c861b6286c --manifest-operator-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:718ca346d5499cccb4de98c1f858c9a9a13bbf429624226f466c3ee2c14ebf40 --asset-input-dir=/assets/tls --asset-output-dir=/assets/kube-apiserver-bootstrap --config-output-file=/assets/kube-apiserver-bootstrap/config --cluster-config-file=/assets/manifests/cluster-network-02-config.yml
/usr/bin/cluster-config-operator render --config-output-file=/assets/config-bootstrap/config --asset-input-dir=/assets/tls --asset-output-dir=/assets/config-bootstrap
/usr/bin/cluster-etcd-operator render --etcd-ca=/assets/tls/etcd-ca-bundle.crt --etcd-metric-ca=/assets/tls/etcd-metric-ca-bundle.crt --manifest-etcd-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:aba3c59eb6d088d61b268f83b034230b3396ce67da4f6f6d49201e55efebc6b2 --etcd-discovery-domain=test.example.com --manifest-cluster-etcd-operator-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:9f7a02df3a5d91326d95e444e2e249f8205632ae986d6dccc7f007ec65c8af77 --manifest-setup-etcd-env-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:31dfdca3584982ed5a82d3017322b7d65a491ab25080c427f3f07d9ce93c52e2 --manifest-kube-client-agent-image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:8eb481214103d8e0b5fe982ffd682f838b969c8ff7d4f3ed4f83d4a444fb841b --asset-input-dir=/assets/tls --asset-output-dir=/assets/etcd-bootstrap --config-output-file=/assets/etcd-bootstrap/config --cluster-config-file=/assets/manifests/cluster-network-02-config.yml
render --output-dir=/assets/cvo-bootstrap --release-image=registry.openshift4.example.com/ocp4/openshift4@sha256:4a461dc23a9d323c8bd7a8631bed078a9e5eec690ce073f78b645c83fb4cdf74
/usr/bin/grep -oP Managed /manifests/0000_12_etcd-operator_01_operator.cr.yaml
$ crictl pods

POD ID              CREATED             STATE               NAME                                                                  NAMESPACE                             ATTEMPT
17a978b9e7b1e       3 minutes ago       Ready               bootstrap-kube-apiserver-bootstrap.openshift4.example.com             kube-system                           24
8a0f79f38787a       3 minutes ago       Ready               bootstrap-kube-scheduler-bootstrap.openshift4.example.com             kube-system                           4
1a707da797173       3 minutes ago       Ready               bootstrap-kube-controller-manager-bootstrap.openshift4.example.com    kube-system                           4
0461d2caa2753       3 minutes ago       Ready               cloud-credential-operator-bootstrap.openshift4.example.com            openshift-cloud-credential-operator   4
ab6519286f65a       3 minutes ago       Ready               bootstrap-cluster-version-operator-bootstrap.openshift4.example.com   openshift-cluster-version             2
457a7a46ec486       8 hours ago         Ready               bootstrap-machine-config-operator-bootstrap.openshift4.example.com    default                               0
e4df49b4d36a1       8 hours ago         Ready               etcd-bootstrap-member-bootstrap.openshift4.example.com                openshift-etcd                        0

如果驗證無問題,則可以一邊繼續下面的步驟一邊觀察日誌:journalctl -b -f -u bootkube.service

RHCOS 的默認用戶是 core,如果想獲取 root 權限,可以執行命令 sudo su(不需要輸入密碼)。

Master

控制節點和之前類似,先創建虛擬機,然後修改引導參數,引導參數調整為:

ip=192.168.57.62::192.168.57.1:255.255.255.0:master1.openshift4.example.com:ens192:none nameserver=192.168.57.60 coreos.inst.install_dev=sda coreos.inst.image_url=http://192.168.57.60:8080/install/rhcos-4.4.3-x86_64-metal.x86_64.raw.gz coreos.inst.ignition_url=http://192.168.57.60:8080/ignition/master.ign 

控制節點安裝成功後會重啟一次,之後同樣可以從基礎節點通過 SSH 密鑰登錄。

然後重複相同的步驟創建其他兩台控制節點,注意修改引導參數(IP 和主機名)。先不急着創建計算節點,先在基礎節點執行以下命令完成生產控制平面的創建:

$ openshift-install --dir=/ocpinstall wait-for bootstrap-complete --log-level=debug

DEBUG OpenShift Installer 4.4.5
DEBUG Built from commit 15eac3785998a5bc250c9f72101a4a9cb767e494
INFO Waiting up to 20m0s for the Kubernetes API at https://api.openshift4.example.com:6443...
INFO API v1.17.1 up
INFO Waiting up to 40m0s for bootstrapping to complete...
DEBUG Bootstrap status: complete
INFO It is now safe to remove the bootstrap resources

待出現 It is now safe to remove the bootstrap resources 提示之後,從負載均衡器中刪除引導主機,本文使用的是 Envoy,只需從 cds.yaml 中刪除引導主機的 endpoint,然後重新加載就好了。

觀察引導節點的日誌:

$ journalctl -b -f -u bootkube.service

...
Jun 05 00:24:12 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:12.108179       1 waitforceo.go:67] waiting on condition EtcdRunningInCluster in etcd CR /cluster to be True.
Jun 05 00:24:21 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:21.595680       1 waitforceo.go:67] waiting on condition EtcdRunningInCluster in etcd CR /cluster to be True.
Jun 05 00:24:26 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:26.250214       1 waitforceo.go:67] waiting on condition EtcdRunningInCluster in etcd CR /cluster to be True.
Jun 05 00:24:26 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:26.306421       1 waitforceo.go:67] waiting on condition EtcdRunningInCluster in etcd CR /cluster to be True.
Jun 05 00:24:29 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:29.097072       1 waitforceo.go:64] Cluster etcd operator bootstrapped successfully
Jun 05 00:24:29 bootstrap.openshift4.example.com bootkube.sh[12571]: I0605 00:24:29.097306       1 waitforceo.go:58] cluster-etcd-operator bootstrap etcd
Jun 05 00:24:29 bootstrap.openshift4.example.com podman[16531]: 2020-06-05 00:24:29.120864426 +0000 UTC m=+17.965364064 container died 77971b6ca31755a89b279fab6f9c04828c4614161c2e678c7cba48348e684517 (image=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:9f7a02df3a5d91326d95e444e2e249f8205632ae986d6dccc7f007ec65c8af77, name=recursing_cerf)
Jun 05 00:24:29 bootstrap.openshift4.example.com bootkube.sh[12571]: bootkube.service complete

Worker

計算節點和之前類似,先創建虛擬機,然後修改引導參數,引導參數調整為:

ip=192.168.57.65::192.168.57.1:255.255.255.0:worker1.openshift4.example.com:ens192:none nameserver=192.168.57.60 coreos.inst.install_dev=sda coreos.inst.image_url=http://192.168.57.60:8080/install/rhcos-4.4.3-x86_64-metal.x86_64.raw.gz coreos.inst.ignition_url=http://192.168.57.60:8080/ignition/worker.ign 

計算節點安裝成功后也會重啟一次,之後同樣可以從基礎節點通過 SSH 密鑰登錄。

然後重複相同的步驟創建其他計算節點,注意修改引導參數(IP 和主機名)。

登錄集群

可以通過導出集群 kubeconfig 文件以默認系統用戶身份登錄到集群。kubeconfig 文件包含有關 CLI 用於將客戶端連接到正確的集群和 API Server 的集群信息,該文件在 OCP 安裝期間被創建。

$ mkdir ~/.kube
$ cp /ocpinstall/auth/kubeconfig ~/.kube/config
$ oc whoami
system:admin

批准 CSR

將節點添加到集群時,會為添加的每台節點生成兩個待處理證書籤名請求(CSR)。必須確認這些 CSR 已獲得批准,或者在必要時自行批准。

$ oc get node

NAME                             STATUS   ROLES           AGE     VERSION
master1.openshift4.example.com   Ready    master,worker   6h25m   v1.17.1
master2.openshift4.example.com   Ready    master,worker   6h39m   v1.17.1
master3.openshift4.example.com   Ready    master,worker   6h15m   v1.17.1
worker1.openshift4.example.com   NotReady worker          5h8m    v1.17.1
worker2.openshift4.example.com   NotReady worker          5h9m    v1.17.1

輸出列出了創建的所有節點。查看掛起的證書籤名請求(CSR),並確保添加到集群的每台節點都能看到具有 PendingApproved 狀態的客戶端和服務端請求。針對 Pending 狀態的 CSR 批准請求:

$ oc adm certificate approve xxx

或者執行以下命令批准所有 CSR:

$ oc get csr -ojson | jq -r '.items[] | select(.status == {} ) | .metadata.name' | xargs oc adm certificate approve

Operator 自動初始化

控制平面初始化后,需要確認所有的 Operator 都處於可用的狀態,即確認所有 Operator 的 Available 字段值皆為 True

$ oc get clusteroperators

NAME                                       VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE
authentication                             4.4.5     True        False         False      150m
cloud-credential                           4.4.5     True        False         False      7h7m
cluster-autoscaler                         4.4.5     True        False         False      6h12m
console                                    4.4.5     True        False         False      150m
csi-snapshot-controller                    4.4.5     True        False         False      6h13m
dns                                        4.4.5     True        False         False      6h37m
etcd                                       4.4.5     True        False         False      6h19m
image-registry                             4.4.5     True        False         False      6h12m
ingress                                    4.4.5     True        False         False      150m
insights                                   4.4.5     True        False         False      6h13m
kube-apiserver                             4.4.5     True        False         False      6h15m
kube-controller-manager                    4.4.5     True        False         False      6h36m
kube-scheduler                             4.4.5     True        False         False      6h36m
kube-storage-version-migrator              4.4.5     True        False         False      6h36m
machine-api                                4.4.5     True        False         False      6h37m
machine-config                             4.4.5     True        False         False      6h36m
marketplace                                4.4.5     True        False         False      6h12m
monitoring                                 4.4.5     True        False         False      6h6m
network                                    4.4.5     True        False         False      6h39m
node-tuning                                4.4.5     True        False         False      6h38m
openshift-apiserver                        4.4.5     True        False         False      6h14m
openshift-controller-manager               4.4.5     True        False         False      6h12m
openshift-samples                          4.4.5     True        False         False      6h11m
operator-lifecycle-manager                 4.4.5     True        False         False      6h37m
operator-lifecycle-manager-catalog         4.4.5     True        False         False      6h37m
operator-lifecycle-manager-packageserver   4.4.5     True        False         False      6h15m
service-ca                                 4.4.5     True        False         False      6h38m
service-catalog-apiserver                  4.4.5     True        False         False      6h38m
service-catalog-controller-manager         4.4.5     True        False         False      6h39m
storage                                    4.4.5     True        False         False      6h12m

如果 Operator 不正常,需要進行問題診斷和修復。

完成安裝

最後一步,完成集群的安裝,執行以下命令:

$ openshift-install --dir=/ocpinstall wait-for install-complete --log-level=debug

注意最後提示訪問 Web Console 的網址及用戶密碼。如果密碼忘了也沒關係,可以查看文件 /ocpinstall/auth/kubeadmin-password 來獲得密碼。

本地訪問 Web Console,需要添加 hosts:

192.168.57.60 console-openshift-console.apps.openshift4.example.com
192.168.57.60 oauth-openshift.apps.openshift4.example.com

瀏覽器訪問 https://console-openshift-console.apps.openshift4.example.com,輸入上面輸出的用戶名密碼登錄。首次登錄後會提示:

You are logged in as a temporary administrative user. Update the Cluster OAuth configuration to allow others to log in.

我們可以通過 htpasswd 自定義管理員賬號,步驟如下:

htpasswd -c -B -b users.htpasswd admin xxxxx

② 將 users.htpasswd 文件下載到本地。

③ 在 Web Console 頁面打開 Global Configuration

然後找到 OAuth,點擊進入,然後添加 HTPasswd 類型的 Identity Providers,並上傳 users.htpasswd 文件。

④ 退出當前用戶,注意要退出到如下界面:

選擇 htpasswd,然後輸入之前創建的用戶名密碼登錄。

如果退出后出現的就是用戶密碼輸入窗口,實際還是 kube:admin 的校驗,如果未出現如上提示,可以手動輸入 Web Console 地址來自動跳轉。

⑤ 登錄后貌似能看到 Administrator 菜單項,但訪問如 OAuth Details 仍然提示:

oauths.config.openshift.io "cluster" is forbidden: User "admin" cannot get resource "oauths" in API group "config.openshift.io" at the cluster scope

因此需要授予集群管理員權限:

$ oc adm policy add-cluster-role-to-user cluster-admin admin

Web Console 部分截圖:

如果想刪除默認賬號,可以執行以下命令:

$ oc -n kube-system delete secrets kubeadmin

8. 參考資料

  • OpenShift 4.2 vSphere Install with Static IPs
  • OpenShift Container Platform 4.3部署實錄
  • Chapter 1. Installing on bare metal

Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準