標籤: 租車

  • 特斯拉大舉安裝機器人 「X 戰警」投入產能將拉高 50%

    特斯拉大舉安裝機器人 「X 戰警」投入產能將拉高 50%

      美國豪華電動車製造商特斯拉 (Tesla) 宣佈,位於加州費利蒙 (Fremont) 的廠房最近進行了一次大改造、大舉採納機器人,預期到了 2015 年底年產能可望從今年的 35,000 台進一步攀升 50%。   特斯拉 Fremont 組裝廠最近一度暫停生產 2 週、以便升級組裝設備,而最大的變化就在組裝線改採先進的機器人,可把整輛車以最精確的方式舉高,還能節省空間。這些最新的機器人應該很快就能替汽車安裝電池,讓人類不必再負擔如此吃重的工作,同時還能將安裝的時間從原本的 4 分鐘縮短至 2 分鐘。   特斯拉並以電影「X 戰警」的角色為這些機器人命名:查爾斯 (Xavier) 是組裝線入口處的舉重機,任務是把汽車從電軌挪至地板;金鋼狼 (Wolverine)、猛獸 (Beast) 是舉重力量更為強大的機器人;暴風女 (Storm)、鋼人 (Colossus) 位在底盤組裝線的最末端;火神 (Vulcan)、法官 (Havok) 則組隊把車送回電軌。   除了機器人之外,特斯拉也把組裝線改造的更為流暢與自動化,現在一週已能生產約 1,000 輛車,未來有機會透過小幅度的修正把產能進一步拉高。特斯拉本次在 2 週的改造期間內總計安裝了 10 台全球最大的機器人。
    在動力系統 (powertrain) 的製作方面,特斯拉也增添了高階機器人,可將電池的日處理量從原本的 80 萬顆拉升至 100 萬顆。     (Source:

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

    【其他文章推薦】

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

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

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

    ※超省錢租車方案

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

  • Model X 鷹翼門問題多 恐延至 2017 年問世

    Model X 鷹翼門問題多 恐延至 2017 年問世

      美國豪華電動車製造商特斯拉 (Tesla ) 為何要將電動休旅車 Model X  的發表時間點從原先的 2015 年第二季延後到第三季?大摩(Morgan Stanley) 認為,這可能是與 Model X 的鷹翼門 (falcon doors) 有關。   MarketWatch、ValueWalk 18 日報導,大摩分析師 Adam Jonas 17 日發表研究報告指出,鷹翼門的設計與機械原理頗為複雜,它擁有 2 個鏈接點,而傳統的鷗翼門 (gull-wing doors) 則只有一個鏈接點。   使用鷹翼門的目的是要讓 Model X 在狹窄的空間 (例如停車場與車庫) 也能順利開門。不過,大摩認為,鷹翼門有 2 個鏈接點,開啟後所需的空間恐怕會比鷗翼門還要多。   大摩猜測,特斯拉可能會再度推延 Model X 的發表時程,也許會遞延至 2017 年初。不過,該證券認為特斯拉不會輕易放棄鷗翼門,因為這會是 Model X 的一大賣點。     (Source:

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

  • 第五屆新能源汽車峰會暨展覽會2014完美落幕好評如潮

    第五屆新能源汽車峰會暨展覽會2014於11月12-14日在中國北京海航大廈萬豪酒店召開。大會由中國汽車工業協會和決策者會議聯合主辦,交通大學汽車工程研究院協辦。主題為新增長局勢下的中國新能源汽車產業動態聚焦,來自國家環保部、國家發改委、北京市科委、中國汽車工業協會、全國乘用車市場訊息聯席會、中國一汽、北汽、吉利、重慶長安新能源、奇瑞新能源汽車、海堅電機、三菱電機、海科新能源等政府協會整車廠商和核心零部件公司、科研機構和媒體機構等集聚一堂,探討新能源整車商專案、戰略規劃以及對核心設備的需求、對於新能源汽車電氣以及動力系統、電控系統、智慧汽車創新、動力電池沖換電基建建設系統的案例分析以及核心技術。

    第五屆新能源汽車峰會暨展覽會2014自確定舉辦以來,一直受到了業內廣泛關注。它的成長與輝煌離不開您的大力支持。對此,我們要特別感謝所有的支持機構,使大會更具專業性;所有的嘉賓,在大會上與所有行業人士分享最新資訊與觀點;所有的贊助商,對於大會工作的理解與支持;所有的媒體朋友們,在大會前夕所做的宣傳與付出的努力。

    三天的會議期間,我們聆聽到了眾多演講嘉賓精彩紛呈的演說。

    中國汽車工業協會副秘書長葉盛基上臺致大會歡迎詞,他對本屆峰會召開表示熱烈的祝賀,對各位的到來和深度的參與表示衷心的感謝,同時對長期以來支持和關注中國汽車工業發展,以及中國新能源汽車發展的各界人士表示誠摯的謝意。
    國家環境保護部落實大氣污染防治司大氣處副處長汪濤為大家分享了落實大氣污染防治行動,加強機動車環保達標監管的這方面課題。
    國家發展和改革委員會能源研究所清潔發展機制項目管理中心康豔兵給我們作關於生態文明背景下我國新能源汽車產業發展的主題分享。
    北京市科學技術委員會新能源與新材料處處長許心超發言的題目是北京新能源汽車產業發展實踐。
    中國第一汽車集團技術中心電動車部的部長劉明輝博士做了一汽新能源汽車技術創新與展望的報告。
    重慶長安新能源汽車有限公司副總經理周安健的演講題目是長安新能源電控系統的自主研發。
    奇瑞新能源汽車技術有限公司副總經理孫衛健演講的題目是電商時代-新能源汽車行銷模式之探索。
    吉利電子傳動有限公司技術部部長于海生的演講主題是CHS混合動力系統平臺開發。
    上海中科深江電動車輛有限公司總經理、中科院電動汽車研發中心副主任孫江明演講主題是新能源汽車動力總成系統的集成創新。
    北京汽車集團有限公司新能源汽車管理部高級工程師王智文分享了新能源發力元年的北汽集團純電動汽車產業佈局。
    上海中科力帆電動汽車有限公司副總經理夏先明分享了力帆新能源汽車產業模式與創新技術—換電。
    全國乘用車市場訊息聯席會秘書長助理孫木子的演講是關於從市場角度談新能源汽車乘用車的熱門話題。
    山東省汽車行業協會常務副會長兼秘書長魏學勤就山東省新能源汽車產業發展現狀與趨勢進行演講。
    中國電源工業協會常務副理事長方英民分享的主題是新能源汽車與鋰電池成組管理。
    Kopis Group總裁Tim WEAVER的演講主題是政府刺激和政策導向在新能源汽車推廣中的作用。
    北京理工大學機械與車輛學院車輛工程系副主任何洪文的演講主題是汽車混合動力系統控制及能量管理。
    高工產業研究院(GGII)院長張小飛分享了新能源汽車巡迴成果報告。
    國家863電動車重大專項動力電池測試中心主任王子冬圍繞電動車的商業模式開發動力電池系統進行主題分享。
    清華大學汽車安全與節能國家重點實驗室副主任陳全世探討了中國新能源汽車技術及產業發展的幾個問題。
    李爾集團高功率電子開發工程經理狄新輝的演講主題是車載充電機——技術領先成本優化的新能源技術。
    海堅電機首席執行官Jae Hak KIM的演講主題是非稀土磁鐵永磁電機在電動汽車上的應用。
    常州海科新能源技術有限公司董事長兼總經理廖越峰的演講主題是飛輪動力技術的研發現狀及發展方向。
    安徽巨一自動化裝備有限公司M&C事業部總經理王淑旺分享了ISO26262 在電驅動產品開發中的應用。
    富華德電子(東莞)有限公司總工程師王樹曉分享了超級電容在汽車上的應用
    微宏動力系統(湖州)有限公司技術中心主任鄭卓群博士的演講主題是快速充電電池技術在電動汽車上的應用。
    上海國際汽車城(集團)有限公司副總經理曹光宇分享了上海電動汽車國際示範區商業模式探索。
    電車匯創始人辛蒂嘉就新能源汽車與互聯網展開討論。
    三菱電機機電(上海)有限公司汽車電源模組事業部副經理及設計部部長Khalid HUSSEIN先生的演講主題是應用於電動汽車的先進功率模組。

    大會現場,我們收到了許多人的贊許:

    中國汽車工業協會副秘書長葉盛基說到:”我注意到峰會的內容,我覺得既有戰略方面的論壇和研討,也有關於技術的一個應用和融合,我認為非常好,一個論壇應該涉及到不同的層面,而且不同的廣泛程度和深度去研討整個產業發展過程中的重點事件、焦點事件和關鍵事件以及我們產業發展所共鳴的事件,我認為是非常有意義的,對新能源汽車產業的發展有積極的促進作用。”

    中國第一汽車股份有限公司技術中心電動車部劉明輝部長:”這個會我感覺辦的還比較專業,參加會議的都是新能源汽車方面的一些主要的參與者,這裡有整車廠也有一些重要的零部件供應商,說的比較專業的話就是都是一些落實新能源汽車產業化的主要的參與者在這裡,這樣可以讓大家在一個比較好的環境下溝通交流,從我自身感覺通過參加這個會跟很多整車廠有一個很好的交流,同時跟這些零件供應商也有很好的交流。”

    Hofer GmbH & Co. KG陳原:”這是一個交流的很好的場合,我看到有很多的主機廠都在這邊,所有的主機廠都有他們新能源的項目在開展,不僅僅是Hofer公司,當然對Hofer公司來講可以很好的介紹公司的經驗給所以的主機廠,那麼對於產業來講也是一個很好的機會促進溝通,包括一些政府法規的頒佈都是一個非常好的場合。”

    上海鷹峰電子徐颯:”本次峰會,客戶對來的人的專業度還是不錯的,對於我們一個新興的產品來說,關注度和互動還是頗有成效的,我們會考慮明年會繼續參加這個會議的。

    全國乘用車市場訊息聯席會孫木子讚歎道:“非常榮幸參加在北京舉辦的新能源汽車盛會!我們相信隨著用戶接受度的逐步提升,新能源汽車在中國發展將越來越好!”

    Jochem KUEHNLE from DANA said that “Very well organized conference! Excellent presenters and a handed by various technical experts and decision makers of the automobile industry.Different with conference participants would be of interest for the next years’ event! Thanks again to CDMC and everybody else envolved in organizing this great event!”

    上海中科力帆電動汽車有限公司夏先明贊許道:”非常高興參加新能源汽車峰會。受益很大,希望下次再會!”

    吉利電子傳動有限公司於海生表示:”非常榮幸參加此次會議,感謝主辦方的辛勤勞動,對本次會議總體感覺較好。但需要加強對內容和演講嘉賓的要求,對模組進行規劃和梳理。祝大會越辦越好!”

    亞普汽車部件有限公司王傳寶說:“非常專業,對新能源汽車的發展趨勢很有用。”

    重慶長安新能源汽車有限公司萬豔寬表示:“各位領導演講的內容很多,資訊很全,演講人都是本領域的專家、領導,給新能源汽車的發展指明了方向。”

    上海先鋒電聲器材有限公司吳銘亮讚歎道:“非常好的交流平臺,對國內新能源車市友有了全面認識。”

    第一電動網薑永傑贊許道:“大會很國際化,乾貨十足。”

    李爾公司薑慧表示:“Quite deep dive from technology side。”

    除此以外,媒體也是我們大會的一大主角。

    大會合作了共60家行業媒體如:第一電動網、中國汽車要聞、電車匯、蓋世汽車網、AI《汽車製造業》、新華信汽車、節能與新能源汽車網、高工鋰電、中國電動汽車時代網、新能源汽車網、電動汽車網、電動汽車資源網、輕量化線上、汽車材料網、汽車供應商網、汽車製造網、集邦能源、華人電池網、電池中國、車典網、電車之家、中國新能源網、電動汽車獵頭網、中華汽配網、環球汽車網、北極星電力網、赤浪綠色新能源網、全球節能環保網、前瞻網、企業網景、中商情報網、中國商業活動網、價值中國等媒體的支持。

    作為會議主辦方,此次大會飽含著CDMC整個團隊對行業的熱情並全力付出。同時,我們也對行業未來的蓬勃發展寄予殷切的希望!最後,我們想誠懇地邀請各位,在參加大會的同時,不吝為我們提出寶貴的意見,以助我們能在未來新能源汽車峰會上為大家奉獻更多精彩。

    我們也熱切地期盼著,新能源汽車峰會的每一次盛放,都能看見您的身影。

    相約2015,老友再相會、新朋共參與!明年,我們將舉辦從規格到規模、從內容到形式、從資訊到社交更加高大上的新能源汽車峰會暨展覽會。

    第六屆新能源汽車峰會暨展覽會2015大會聯繫:
    邱小姐(Elva Qiu)
    電話:021 63931899轉2041
    手機:18930215786
    QQ:1147789586
    e-mail:

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

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

  • 設計模式系列之一:簡單工廠模式

    設計模式系列之一:簡單工廠模式

    1.1 定義

     簡單工廠模式屬於創建型模式,又稱為靜態工廠方法模式,在簡單工廠模式中,可以根據參數的不同,來返回不同類的實例,簡單工廠模式專門定義一個類來負責創建子類的實例,被創建的類通常有一個共同的父類

    1.2 簡單工廠模式結構圖(簡版)

                                 

     Factory:工廠類,簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類的創建產品類的方法可以被外界直接調用,創建所需的產品對象

     IProduct:抽象產品類,簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口

     Product:具體產品類,是簡單工廠模式的目標類

    1.3 簡單工廠的實現一

     假設有一個電腦的代工生產商,它目前已經可以代工生產聯想電腦了,隨着業務的拓展,這個代工生產商還要生產惠普和mac電腦;

     這樣我們就需要用一個單獨的類來專門生產電腦,這就用到了簡單工廠模式,同時用到了繼承、封裝、多態等面向對象編程的思想,下面我們來實現簡單工廠模式

    1.3.1 產品抽象類

    public abstract class Computer {
        /**
         * 產品的抽象方法,由具體的產品類去實現
         */
        public abstract void start();
    
    }

     

    1.3.2  具體實現類

    public class LenovoComputer extends Computer {
    
        @Override
        public void start() {
            System.out.println("lenovo computer run");
        }
    }
    public class MacComputer extends Computer {
        @Override
        public void start() {
            System.out.println("Mac computer run");
        }
    }
    public class HpComputer extends Computer {
        @Override
        public void start() {
            System.out.println("hp computer run");
        }
    }

    1.3.3  工廠類

    public class ComputerFactory {
        public static Computer createComputer(String type) {
            Computer computer = null;
            switch (type) {
                case "lenovo":
                    computer = new LenovoComputer();
                    break;
                case "hp":
                    computer = new HpComputer();
                    break;
                case "Mac":
                    computer = new MacComputer();
                    break;
                default:
                    break;
            }
            return computer;
        }
    }

    1.3.4  UML類圖

                              

    1.4 優缺點

     優點:

     1. 工廠類含有必要的判斷邏輯,可以決定在什麼時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;實現了對責任的分割,它提供了專門的工廠類用於創建對象

     2. 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。

     3. 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。

    缺點:

     1. 由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。

     2. 使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的複雜度和理解難度。

     3. 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,同樣破壞了“開閉原則”;在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護

     4. 簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構

    1.5 適用場景

     1. 工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。

     2. 客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數

    1.6 模式應用

     1. JDK類庫中廣泛使用了簡單工廠模式,如工具類java.text.DateFormat,它用於格式化一個本地日期或者時間

    public final static DateFormat getDateInstance(); 
    public final static DateFormat getDateInstance(int style); 
    public final static DateFormat getDateInstance(int style,Locale locale);

     2. 獲取不同加密算法的密鑰生成器

    KeyGenerator keyGen=KeyGenerator.getInstance("DESede");

    1.7 開閉原則

     對於上面兩種簡單工廠模式的實現方法,如果我們要添加新的 parser,那勢必要改動到 RuleConfigParserFactory 的代碼,那這是不是違反開閉原則呢?

     實際上,如果不是需要頻繁地添加新的 parser,只是偶爾修改一下 RuleConfigParserFactory 代碼,稍微不符合開閉原則,也是完全可以接受的

     儘管簡單工廠模式的代碼實現中,有多處 if 分支判斷邏輯,違背開閉原則,但權衡擴展性和可讀性,這樣的代碼實現在大多數情況下(比如,不需要頻繁地添加 parser,也沒有太多的 parser)是沒有問題的

     

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

    【其他文章推薦】

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

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

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

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

    ※超省錢租車方案

  • 03 . 二進制部署kubernetes1.18.4

    03 . 二進制部署kubernetes1.18.4

    簡介

    目前生產部署kubernetes集群主要兩種方式

    kubeadm

    Kubeadm是一個K8s部署工具,提供kubeadm init和kubeadm join,用於快速部署Kubernetes集群。

    二進制包

    從github下載發行版的二進制包,手動部署每個組件,組成Kubernetes集群。

    Kubeadm降低部署門檻,但屏蔽了很多細節,遇到問題很難排查。如果想更容易可控,推薦使用二進制包部署Kubernetes集群,雖然手動部署麻煩點,期間可以學習很多工作原理,也利於後期維護。

    二進制部署K8s

    List
    CentOS7.3
    cni-plugins-linux-amd64-v0.8.6.tgz
    etcd-v3.4.9-linux-amd64.tar.gz
    kube-flannel.yml
    kubernetes-server-linux-amd64.tar.gz
    
    角色 IP 組件
    master 192.168.31.71 kube-apiserver,kube-controller-manager,kube-scheduler,etcd
    Node1 192.168.31.74 kube-apiserver,kube-controller-manager,kube-scheduler
    Node2 192.168.31.72 kubelet,kube-proxy,docker etcd

    初始化環境

    # 初始化
    init_security() {
    systemctl stop firewalld
    systemctl disable firewalld &>/dev/null
    setenforce 0
    sed -i '/^SELINUX=/ s/enforcing/disabled/'  /etc/selinux/config
    sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config
    sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config
    systemctl enable sshd crond &> /dev/null
    rpm -e postfix --nodeps
    echo -e "\033[32m [安全配置] ==> OK \033[0m"
    }
    init_security
    
    init_yumsource() {
    if [ ! -d /etc/yum.repos.d/backup ];then
        mkdir /etc/yum.repos.d/backup
    fi
    mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null
    if ! ping -c2 www.baidu.com &>/dev/null    
    then
        echo "您無法上外網,不能配置yum源"
        exit    
    fi
        curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo &>/dev/null
        curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo &>/dev/null
        yum clean all
        timedatectl set-timezone Asia/Shanghai
        echo "nameserver 114.114.114.114" > /etc/resolv.conf
        echo "nameserver 8.8.8.8" >> /etc/resolv.conf
        chattr +i /etc/resolv.conf
        yum -y install ntpdate
        ntpdate -b  ntp1.aliyun.com        # 對時很重要
        echo -e "\033[32m [YUM Source] ==> OK \033[0m"
    }
    init_yumsource
    
    # 關掉swap分區
    swapoff -a
    # 如果想永久關掉swap分區,打開如下文件註釋掉swap哪一行即可.
    sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab #永久
    
    # 配置主機名解析
    tail -3 /etc/hosts
    192.168.0.121 master
    192.168.0.123 node1
    192.168.0.124 node2
    
    # 將橋接的IPv4流量傳遞到iptables的鏈
    cat > /etc/sysctl.d/k8s.conf << EOF
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF
    sysctl --system  # 生效
    
    
    # 升級內核(非必須,只是性能更好)
    wget https://cbs.centos.org/kojifiles/packages/kernel/4.9.220/37.el7/x86_64/kernel-4.9.220-37.el7.x86_64.rpm
      
    rpm -ivh kernel-4.9.220-37.el7.x86_64.rpm
    reboot
    
    

    部署etcd集群

    Etcd 是一個分佈式鍵值存儲系統,Kubernetes使用Etcd進行數據存儲,所以先準備一個Etcd數據庫,為解決Etcd單點故障,應採用集群方式部署,這裏使用3台組建集群,可容忍1台機器故障,當然,你也可以使用5台組建集群,可容忍2台機器故障。

    節點名稱 IP
    etcd-1 192.168.31.71
    etcd-2 192.168.31.72
    etcd-3 192.168.31.73

    注:為了節省機器,這裏與K8s節點機器復用。也可以獨立於k8s集群之外部署,只要apiserver能連接到就行。

    準備cfssl證書生成工具

    cfssl是一個開源的證書管理工具,使用json文件生成證書,相比openssl更方便使用。

    找任意一台服務器操作,這裏用Master節點。

    wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
    wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
    wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
    chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
    mv cfssl_linux-amd64 /usr/local/bin/cfssl
    mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
    mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
    
    生成etcd證書
    創建工作目錄
    mkdir -p ~/TLS/{etcd,k8s}
    
    cd TLS/etcd
    
    自簽CA
    cat > ca-config.json << EOF
    {
      "signing": {
        "default": {
          "expiry": "87600h"
        },
        "profiles": {
          "www": {
             "expiry": "87600h",
             "usages": [
                "signing",
                "key encipherment",
                "server auth",
                "client auth"
            ]
          }
        }
      }
    }
    EOF
    
    cat > ca-csr.json << EOF
    {
        "CN": "etcd CA",
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "names": [
            {
                "C": "CN",
                "L": "Beijing",
                "ST": "Beijing"
            }
        ]
    }
    EOF
    
    生成證書
    cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
    
    ls *pem
    ca-key.pem  ca.pem
    
    使用自簽CA簽發etcd https證書

    創建證書申請文件

    cat > server-csr.json << EOF
    {
        "CN": "etcd",
        "hosts": [
        "192.168.0.121",
        "192.168.0.123",
        "192.168.0.124"
        ],
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "names": [
            {
                "C": "CN",
                "L": "BeiJing",
                "ST": "BeiJing"
            }
        ]
    }
    EOF
    

    注:上述文件hosts字段中IP為所有etcd節點的集群內部通信IP,一個都不能少!為了方便後期擴容可以多寫幾個預留的IP。

    生成證書
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
    
    ls server*pem
    server-key.pem  server.pem
    
    下載etcd二進制文件
    wget https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz
    
    創建工作目錄並解壓二進制包
    mkdir /opt/etcd/{bin,cfg,ssl} -p
    tar zxvf etcd-v3.4.9-linux-amd64.tar.gz
    mv etcd-v3.4.9-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/
    
    # 配置etcd
    cat /opt/etcd/cfg/etcd.conf 
    #[Member]
    ETCD_NAME="etcd-1"
    ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
    ETCD_LISTEN_PEER_URLS="https://192.168.0.121:2380"
    ETCD_LISTEN_CLIENT_URLS="https://192.168.0.121:2379"
    #[Clustering]
    ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.0.121:2380"
    ETCD_ADVERTISE_CLIENT_URLS="https://192.168.0.121:2379"
    ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.0.121:2380,etcd-2=https://192.168.0.123:2380,etcd-3=https://192.168.0.124:2380"
    ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
    ETCD_INITIAL_CLUSTER_STATE="new"
    
    # ETCD_NAME:節點名稱,集群中唯一
    # ETCD_DATA_DIR:數據目錄
    # ETCD_LISTEN_PEER_URLS:集群通信監聽地址
    # ETCD_LISTEN_CLIENT_URLS:客戶端訪問監聽地址
    # ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
    # ETCD_ADVERTISE_CLIENT_URLS:客戶端通告地址
    # ETCD_INITIAL_CLUSTER:集群節點地址
    # ETCD_INITIAL_CLUSTER_TOKEN:集群Token
    # ETCD_INITIAL_CLUSTER_STATE:加入集群的當前狀態,new是新集群,existing表示加入已有集群
    
    systemd管理etcd
    cat > /usr/lib/systemd/system/etcd.service << EOF
    [Unit]
    Description=Etcd Server
    After=network.target
    After=network-online.target
    Wants=network-online.target
    [Service]
    Type=notify
    EnvironmentFile=/opt/etcd/cfg/etcd.conf
    ExecStart=/opt/etcd/bin/etcd \
    --cert-file=/opt/etcd/ssl/server.pem \
    --key-file=/opt/etcd/ssl/server-key.pem \
    --peer-cert-file=/opt/etcd/ssl/server.pem \
    --peer-key-file=/opt/etcd/ssl/server-key.pem \
    --trusted-ca-file=/opt/etcd/ssl/ca.pem \
    --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
    --logger=zap
    Restart=on-failure
    LimitNOFILE=65536
    [Install]
    WantedBy=multi-user.target
    EOF
    
    拷貝剛生成證書及生成的文件拷貝到節點2,節點3
    cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/
    
    scp -r /opt/etcd/ node1:/opt/
    scp -r /opt/etcd/ node2:/opt/
    scp /usr/lib/systemd/system/etcd.service node1:/usr/lib/systemd/system/
    scp /usr/lib/systemd/system/etcd.service node2:/usr/lib/systemd/system/
    
    修改節點2和節點3etcd.conf配置文件
    node-1
    cat /opt/etcd/cfg/etcd.conf 
    #[Member]
    ETCD_NAME="etcd-2"
    ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
    ETCD_LISTEN_PEER_URLS="https://192.168.0.123:2380"
    ETCD_LISTEN_CLIENT_URLS="https://192.168.0.123:2379"
    #[Clustering]
    ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.0.123:2380"
    ETCD_ADVERTISE_CLIENT_URLS="https://192.168.0.123:2379"
    ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.0.121:2380,etcd-2=https://192.168.0.123:2380,etcd-3=https://192.168.0.124:2380"
    ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
    ETCD_INITIAL_CLUSTER_STATE="new"
    
    
    # node-2
    #[Member]
    ETCD_NAME="etcd-3"
    ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
    ETCD_LISTEN_PEER_URLS="https://192.168.0.124:2380"
    ETCD_LISTEN_CLIENT_URLS="https://192.168.0.124:2379"
    #[Clustering]
    ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.0.124:2380"
    ETCD_ADVERTISE_CLIENT_URLS="https://192.168.0.124:2379"
    ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.0.121:2380,etcd-2=https://192.168.0.123:2380,etcd-3=https://192.168.0.124:2380"
    ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
    ETCD_INITIAL_CLUSTER_STATE="new"
    
    # 啟動服務並設置開機自啟
    systemctl daemon-reload
    systemctl start etcd
    systemctl enable etcd
    
    驗證etcd集群狀態
     /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.0.121:2379,https://192.168.0.123:2379,https://192.168.0.124:2379" endpoint healthhttps://192.168.0.124:2379 is healthy: successfully committed proposal: took = 13.213712ms
    https://192.168.0.121:2379 is healthy: successfully committed proposal: took = 12.907787ms
    https://192.168.0.123:2379 is healthy: successfully committed proposal: took = 12.168703ms
            
    # 如果輸出上面信息,就說明集群部署成功。如果有問題第一步先看日誌:/var/log/message 或 journalctl -u etcd
    

    安裝docker

    下載安裝docker
    sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    yum -y install docker-ce-19.03.9-3.el7
    
    配置docker鏡像源
    mkdir /etc/docker
    cat > /etc/docker/daemon.json << EOF
    {
      "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
    }
    EOF
    
    啟動並設置開機自啟
    systemctl daemon-reload
    systemctl start docker
    systemctl enable docker
    

    部署Master Node

    生成kube-apiserver證書

    1. 自簽證書頒發機構(CA)

    cat > ca-config.json << EOF
    {
      "signing": {
        "default": {
          "expiry": "87600h"
        },
        "profiles": {
          "kubernetes": {
             "expiry": "87600h",
             "usages": [
                "signing",
                "key encipherment",
                "server auth",
                "client auth"
            ]
          }
        }
      }
    }
    EOF
    cat > ca-csr.json << EOF
    {
        "CN": "kubernetes",
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "names": [
            {
                "C": "CN",
                "L": "Beijing",
                "ST": "Beijing",
                "O": "k8s",
                "OU": "System"
            }
        ]
    }
    EOF
    
    # 生成證書
    cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
    
    ls *pem
    ca-key.pem  ca.pem
    
    使用自簽CA簽發kube-apiserver https 證書
    cat /root/TLS/k8s/server-csr.json 
    {
        "CN": "kubernetes",
        "hosts": [
          "10.0.0.1",
          "127.0.0.1",
          "192.168.0.121",
          "192.168.0.123",
          "192.168.0.124",
          "192.168.0.125",
          "192.168.0.100",
          "kubernetes",
          "kubernetes.default",
          "kubernetes.default.svc",
          "kubernetes.default.svc.cluster",
          "kubernetes.default.svc.cluster.local"
        ],
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "names": [
            {
                "C": "CN",
                "L": "BeiJing",
                "ST": "BeiJing",
                "O": "k8s",
                "OU": "System"
            }
        ]
    }
    
    # 上述文件hosts字段中IP為所有Master/LB/VIP IP,一個都不能少!為了方便後期擴容可以多寫幾個預留的IP。
    
    # 生成證書
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
    
    ls server*pem
    server-key.pem  server.pem
    
    下載解壓二進制包
    wget https://dl.k8s.io/v1.18.4/kubernetes-server-linux-amd64.tar.gz
    mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs} 
    tar zxvf kubernetes-server-linux-amd64.tar.gz
    cd kubernetes/server/bin
    cp kube-apiserver kube-scheduler kube-controller-manager /opt/kubernetes/bin
    cp kubectl /usr/bin/
    
    部署kube-apiserver
    cat /opt/kubernetes/cfg/kube-apiserver.conf 
    KUBE_APISERVER_OPTS="--logtostderr=false \
    --v=2 \
    --log-dir=/opt/kubernetes/logs \
    --etcd-servers=https://192.168.0.121:2379,https://192.168.0.123:2379,https://192.168.0.124:2379 \
    --bind-address=192.168.0.121 \
    --secure-port=6443 \
    --advertise-address=192.168.0.121 \
    --allow-privileged=true \
    --service-cluster-ip-range=10.0.0.0/24 \
    --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
    --authorization-mode=RBAC,Node \
    --enable-bootstrap-token-auth=true \
    --token-auth-file=/opt/kubernetes/cfg/token.csv \
    --service-node-port-range=30000-32767 \
    --kubelet-client-certificate=/opt/kubernetes/ssl/server.pem \
    --kubelet-client-key=/opt/kubernetes/ssl/server-key.pem \
    --tls-cert-file=/opt/kubernetes/ssl/server.pem  \
    --tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \
    --client-ca-file=/opt/kubernetes/ssl/ca.pem \
    --service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
    --etcd-cafile=/opt/etcd/ssl/ca.pem \
    --etcd-certfile=/opt/etcd/ssl/server.pem \
    --etcd-keyfile=/opt/etcd/ssl/server-key.pem \
    --audit-log-maxage=30 \
    --audit-log-maxbackup=3 \
    --audit-log-maxsize=100 \
    --audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
    
    
    # –logtostderr:啟用日誌
    # —v:日誌等級
    # –log-dir:日誌目錄
    # –etcd-servers:etcd集群地址
    # –bind-address:監聽地址
    # –secure-port:https安全端口
    # –advertise-address:集群通告地址
    # –allow-privileged:啟用授權
    # –service-cluster-ip-range:Service虛擬IP地址段
    # –enable-admission-plugins:准入控制模塊
    # –authorization-mode:認證授權,啟用RBAC授權和節點自管理
    # –enable-bootstrap-token-auth:啟用TLS bootstrap機制
    # –token-auth-file:bootstrap token文件
    # –service-node-port-range:Service nodeport類型默認分配端口範圍
    # –kubelet-client-xxx:apiserver訪問kubelet客戶端證書
    # –tls-xxx-file:apiserver https證書
    # –etcd-xxxfile:連接Etcd集群證書
    # –audit-log-xxx:審計日誌
    
    拷貝剛生成證書
    cp ~/TLS/k8s/ca*pem ~/TLS/k8s/server*pem /opt/kubernetes/ssl/
    
    啟用TLS Bootstrapping機制

    TLS Bootstraping:Master apiserver啟用TLS認證后,Node節點kubelet和kube-proxy要與kube-apiserver進行通信,必須使用CA簽發的有效證書才可以,當Node節點很多時,這種客戶端證書頒發需要大量工作,同樣也會增加集群擴展複雜度。為了簡化流程,Kubernetes引入了TLS bootstraping機制來自動頒發客戶端證書,kubelet會以一個低權限用戶自動向apiserver申請證書,kubelet的證書由apiserver動態簽署。所以強烈建議在Node上使用這種方式,目前主要用於kubelet,kube-proxy還是由我們統一頒發一個證書

    TLS bootstraping 工作流程

    創建上述配置文件中token文件

    cat > /opt/kubernetes/cfg/token.csv << EOF
    c47ffb939f5ca36231d9e3121a252940,kubelet-bootstrap,10001,"system:node-bootstrapper"
    EOF
    
    # 格式:token,用戶名,UID,用戶組
    

    token也可自行生成替換

    head -c 16 /dev/urandom | od -An -t x | tr -d ' '
    
    systemd管理apiserver
    cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
    [Unit]
    Description=Kubernetes API Server
    Documentation=https://github.com/kubernetes/kubernetes
    [Service]
    EnvironmentFile=/opt/kubernetes/cfg/kube-apiserver.conf
    ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
    EOF
    
    啟動設置開機啟動
    systemctl daemon-reload
    systemctl start kube-apiserver
    systemctl enable kube-apiserver
    
    授權kubelet-bootstrap用戶允許請求證書
    kubectl create clusterrolebinding kubelet-bootstrap \
    --clusterrole=system:node-bootstrapper \
    --user=kubelet-bootstrap
    

    部署kube-controller-manager

    創建配置文件
    cat /opt/kubernetes/cfg/kube-controller-manager.conf 
    KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \
    --v=2 \
    --log-dir=/opt/kubernetes/logs \
    --leader-elect=true \
    --master=127.0.0.1:8080 \
    --bind-address=127.0.0.1 \
    --allocate-node-cidrs=true \
    --cluster-cidr=10.244.0.0/16 \
    --service-cluster-ip-range=10.0.0.0/24 \
    --cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \
    --cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem  \
    --root-ca-file=/opt/kubernetes/ssl/ca.pem \
    --service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \
    --experimental-cluster-signing-duration=87600h0m0s"
    
    # –master:通過本地非安全本地端口8080連接apiserver。
    # –leader-elect:當該組件啟動多個時,自動選舉(HA)
    # –cluster-signing-cert-file/–cluster-signing-key-file:自動為kubelet頒發證書的CA,與apiserver保持一致
    
    systemd管理controller-manager
    cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
    [Unit]
    Description=Kubernetes Controller Manager
    Documentation=https://github.com/kubernetes/kubernetes
    [Service]
    EnvironmentFile=/opt/kubernetes/cfg/kube-controller-manager.conf
    ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
    EOF
    
    啟動設置開機啟動
    systemctl daemon-reload
    systemctl start kube-controller-manager
    systemctl enable kube-controller-manager
    

    部署kube-scheduler

    創建配置文件
    cat /opt/kubernetes/cfg/kube-scheduler.conf 
    KUBE_SCHEDULER_OPTS="--logtostderr=false --v=2 --log-dir=/opt/kubernetes/logs --leader-elect --master=127.0.0.1:8080 --bind-address=127.0.0.1"
    
    # –master:通過本地非安全本地端口8080連接apiserver。
    # –leader-elect:當該組件啟動多個時,自動選舉(HA)
    
    systemd管理scheduler
    cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
    [Unit]
    Description=Kubernetes Scheduler
    Documentation=https://github.com/kubernetes/kubernetes
    [Service]
    EnvironmentFile=/opt/kubernetes/cfg/kube-scheduler.conf
    ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
    EOF
    
    啟動並設置開機自啟動
    systemctl daemon-reload
    systemctl start kube-scheduler
    systemctl enable kube-scheduler
    
    查看集群狀態
    # 所有組件都已經啟動成功,通過kubectl工具查看當前集群組件狀態:
    kubectl get cs
    NAME                 STATUS    MESSAGE             ERROR
    scheduler            Healthy   ok                  
    controller-manager   Healthy   ok                  
    etcd-2               Healthy   {"health":"true"}   
    etcd-1               Healthy   {"health":"true"}   
    etcd-0               Healthy   {"health":"true"} 
    

    部署worker node

    下面還是在Master Node上操作,即同時作為Worker Node

    創建工作目錄並拷貝二進制文件

    在所有worker node創建工作目錄

    mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs} 
    

    從master節點拷貝

    cd kubernetes/server/bin
    cp kubelet kube-proxy /opt/kubernetes/bin   # 本地拷貝,註釋這裏操作還是master節點,
    

    部署kubelet

    創建配置文件
    cat /opt/kubernetes/cfg/kubelet.conf 
    KUBELET_OPTS="--logtostderr=false \
    --v=2 \
    --log-dir=/opt/kubernetes/logs \
    --hostname-override=master \
    --network-plugin=cni \
    --kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
    --bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
    --config=/opt/kubernetes/cfg/kubelet-config.yml \
    --cert-dir=/opt/kubernetes/ssl \
    --pod-infra-container-image=lizhenliang/pause-amd64:3.0"
    
    
    # –hostname-override:显示名稱,集群中唯一
    # –network-plugin:啟用CNI
    # –kubeconfig:空路徑,會自動生成,後面用於連接apiserver
    # –bootstrap-kubeconfig:首次啟動向apiserver申請證書
    # –config:配置參數文件
    # –cert-dir:kubelet證書生成目錄
    # –pod-infra-container-image:管理Pod網絡容器的鏡像
    
    配置參數文件
    cat > /opt/kubernetes/cfg/kubelet-config.yml << EOF
    kind: KubeletConfiguration
    apiVersion: kubelet.config.k8s.io/v1beta1
    address: 0.0.0.0
    port: 10250
    readOnlyPort: 10255
    cgroupDriver: cgroupfs
    clusterDNS:
    - 10.0.0.2
    clusterDomain: cluster.local 
    failSwapOn: false
    authentication:
      anonymous:
        enabled: false
      webhook:
        cacheTTL: 2m0s
        enabled: true
      x509:
        clientCAFile: /opt/kubernetes/ssl/ca.pem 
    authorization:
      mode: Webhook
      webhook:
        cacheAuthorizedTTL: 5m0s
        cacheUnauthorizedTTL: 30s
    evictionHard:
      imagefs.available: 15%
      memory.available: 100Mi
      nodefs.available: 10%
      nodefs.inodesFree: 5%
    maxOpenFiles: 1000000
    maxPods: 110
    EOF
    
    生成bootstrap.kubeconfig文件
    KUBE_APISERVER="https://192.168.0.121:6443" # apiserver IP:PORT
    
    TOKEN="c47ffb939f5ca36231d9e3121a252940" # 與token.csv里保持一致
    
    # 生成 kubelet bootstrap kubeconfig 配置文件
    kubectl config set-cluster kubernetes \
      --certificate-authority=/opt/kubernetes/ssl/ca.pem \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=bootstrap.kubeconfig
      
      
    kubectl config set-credentials "kubelet-bootstrap" \
      --token=${TOKEN} \
      --kubeconfig=bootstrap.kubeconfig
      
      
    kubectl config set-context default \
      --cluster=kubernetes \
      --user="kubelet-bootstrap" \
      --kubeconfig=bootstrap.kubeconfig
      
      
    kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
    
    # 拷貝到配置文件路徑
    cp bootstrap.kubeconfig /opt/kubernetes/cfg
    
    systemd管理kubelet
    cat > /usr/lib/systemd/system/kubelet.service << EOF
    [Unit]
    Description=Kubernetes Kubelet
    After=docker.service
    [Service]
    EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
    ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
    Restart=on-failure
    LimitNOFILE=65536
    [Install]
    WantedBy=multi-user.target
    EOF
    
    啟動並設置開機自啟
    systemctl daemon-reload
    systemctl start kubelet
    systemctl enable kubelet
    
    批准kubelet證書並加入集群
    # 查看kubelet證書請求
    kubectl get csr
    NAME                                                   AGE    SIGNERNAME                                    REQUESTOR           CONDITION
    node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A   6m3s   kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Pending
    
    # 批准申請
    kubectl certificate approve node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A
    
    # 查看節點
    kubectl get node
    NAME     STATUS   ROLES    AGE    VERSION
    master   Ready    <none>   123m   v1.18.4
    
    # 由於網絡插件還沒有部署,節點會沒有準備就緒 NotReady
    

    部署kube-proxy

    創建配置文件
    cat > /opt/kubernetes/cfg/kube-proxy.conf << EOF
    KUBE_PROXY_OPTS="--logtostderr=false \\
    --v=2 \\
    --log-dir=/opt/kubernetes/logs \\
    --config=/opt/kubernetes/cfg/kube-proxy-config.yml"
    EOF
    
    創建參數文件
    cat > /opt/kubernetes/cfg/kube-proxy-config.yml << EOF
    kind: KubeProxyConfiguration
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    metricsBindAddress: 0.0.0.0:10249
    clientConnection:
      kubeconfig: /opt/kubernetes/cfg/kube-proxy.kubeconfig
    hostnameOverride: k8s-master
    clusterCIDR: 10.0.0.0/24
    EOF
    
    生成kube-proxy.kubeconfig文件

    生成kube-proxy證書

    # 切換工作目錄
    cd TLS/k8s
    
    # 創建證書請求文件
    cat > kube-proxy-csr.json << EOF
    {
      "CN": "system:kube-proxy",
      "hosts": [],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [
        {
          "C": "CN",
          "L": "BeiJing",
          "ST": "BeiJing",
          "O": "k8s",
          "OU": "System"
        }
      ]
    }
    EOF
    
    # 生成證書
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
    
    ls kube-proxy*pem
    kube-proxy-key.pem  kube-proxy.pem
    
    生成kubeconfig文件
    KUBE_APISERVER="https://192.168.0.121:6443"
    
    kubectl config set-cluster kubernetes \
      --certificate-authority=/opt/kubernetes/ssl/ca.pem \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=kube-proxy.kubeconfig
      
    kubectl config set-credentials kube-proxy \
      --client-certificate=./kube-proxy.pem \
      --client-key=./kube-proxy-key.pem \
      --embed-certs=true \
      --kubeconfig=kube-proxy.kubeconfig
      
    kubectl config set-context default \
      --cluster=kubernetes \
      --user=kube-proxy \
      --kubeconfig=kube-proxy.kubeconfig
      
    kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
    
    # 拷貝配置文件到指定路徑
    cp kube-proxy.kubeconfig /opt/kubernetes/cfg/
    
    systemd管理kube-proxy
    cat > /usr/lib/systemd/system/kube-proxy.service << EOF
    [Unit]
    Description=Kubernetes Proxy
    After=network.target
    [Service]
    EnvironmentFile=/opt/kubernetes/cfg/kube-proxy.conf
    ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
    Restart=on-failure
    LimitNOFILE=65536
    [Install]
    WantedBy=multi-user.target
    EOF
    
    啟動並設置開機啟動
    systemctl daemon-reload
    systemctl start kube-proxy
    systemctl enable kube-proxy
    

    部署CNI網絡

    準備二進制文件
    wget https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz
      
    # 解壓二進制文件並移動到默認工作目錄
    mkdir /opt/cni/bin
    tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
    
    # 部署cni網絡
    wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    sed -i -r "s#quay.io/coreos/flannel:.*-amd64#lizhenliang/flannel:v0.12.0-amd64#g" kube-flannel.yml
    
    # 默認鏡像地址無法訪問,修改為docker hub鏡像倉庫。
    kubectl apply -f kube-flannel.yml
    
    kubectl get pods -n kube-system
    NAME                          READY   STATUS    RESTARTS   AGE
    kube-flannel-ds-amd64-2pc95   1/1     Running   0          72s
    
    kubectl get node
    NAME         STATUS   ROLES    AGE   VERSION
    master   Ready    <none>   41m   v1.18.4
    # 部署好網絡插件,Node準備就緒
    
    授權apiserver訪問kubelet
    cat > apiserver-to-kubelet-rbac.yaml << EOF
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      annotations:
        rbac.authorization.kubernetes.io/autoupdate: "true"
      labels:
        kubernetes.io/bootstrapping: rbac-defaults
      name: system:kube-apiserver-to-kubelet
    rules:
      - apiGroups:
          - ""
        resources:
          - nodes/proxy
          - nodes/stats
          - nodes/log
          - nodes/spec
          - nodes/metrics
          - pods/log
        verbs:
          - "*"
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: system:kube-apiserver
      namespace: ""
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:kube-apiserver-to-kubelet
    subjects:
      - apiGroup: rbac.authorization.k8s.io
        kind: User
        name: kubernetes
    EOF
    
    kubectl apply -f apiserver-to-kubelet-rbac.yaml
    
    新增加Worker Node

    拷貝已部署好的Node相關文件到新節點

    scp -r /opt/kubernetes/ node1:/opt/
    scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service node1:/usr/lib/systemd/system
    
    scp -r /opt/cni/ node1:/opt/
    scp /opt/kubernetes/ssl/ca.pem node1:/opt/kubernetes/ssl
    
    刪除kubelet證書和kubeconfig文件
    rm -f /opt/kubernetes/cfg/kubelet.kubeconfig 
    rm -f /opt/kubernetes/ssl/kubelet*
    
    # 這幾個文件是證書申請審批后自動生成的,每個Node不同,必須刪除重新生成。
    
    修改主機名並設置開機自啟動
    vi /opt/kubernetes/cfg/kubelet.conf
    --hostname-override=node1
    
    vi /opt/kubernetes/cfg/kube-proxy-config.yml
    hostnameOverride: node1
    
    # 啟動並設置開機啟動
    systemctl daemon-reload
    systemctl start kubelet
    systemctl enable kubelet
    systemctl start kube-proxy
    systemctl enable kube-proxy
    
    再master上批准Node kubelet證書申請
    kubectl get csr
    NAME                                                   AGE   SIGNERNAME                                    REQUESTOR           CONDITION
    node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro   89s   kubernetes.io/kube-apiserver-client-kubelet   kubelet-bootstrap   Pending
    
    kubectl certificate approve node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro
    
    kubectl get node
    NAME     STATUS   ROLES    AGE    VERSION
    master   Ready    <none>   138m   v1.18.4
    node1    Ready    <none>   120m   v1.18.4
    node2    Ready    <none>   112m   v1.18.4
    

    部署Dashboard

    下載dashboard.yaml文件
    wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
    
    修改yaml配置文件使其端口暴露外部訪問
    wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
      
    # 默認Dashboard只能集群內部訪問,修改Service為NodePort類型,暴露到外部:
    
    vi recommended.yaml
    kind: Service
    apiVersion: v1
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
      name: kubernetes-dashboard
      namespace: kubernetes-dashboard
    spec:
      ports:
        - port: 443
          targetPort: 8443
          nodePort: 30001  # 修改這裏
      type: NodePort   # 修改這裏
      selector:
        k8s-app: kubernetes-dashboard
    
    kubectl apply -f recommended.yaml
    
    kubectl get pods,svc -n kubernetes-dashboard
    NAME                                             READY   STATUS    RESTARTS   AGE
    pod/dashboard-metrics-scraper-694557449d-69x7g   1/1     Running   0          111m
    pod/kubernetes-dashboard-9774cc786-kwgkt         1/1     Running   0          111m
    
    NAME                                TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
    service/dashboard-metrics-scraper   ClusterIP   10.0.0.3     <none>        8000/TCP        111m
    service/kubernetes-dashboard        NodePort    10.0.0.122   <none>        443:30001/TCP   111m
    
    創建service account並綁定默認cluster-admin管理員集群角色
    kubectl create serviceaccount dashboard-admin -n kube-system
    kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
    kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
    
    # 接下來訪問https://node ip:30001
    # 然後將上面過濾出來的token複製上面即可訪問dashboard
    
    # 我們可以部署個Nginx測試下集群可用性
    kubectl run --generator=run-pod/v1 nginx-test2 --image=daocloud.io/library/nginx --port=80 --replicas=1
    
    kubectl get pods -o wide
    kubectl get pods -o wide
    NAME          READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
    nginx-test2   1/1     Running   0          89m   10.244.2.2   node2   <none>           <none>
    
    # 我們去相應的節點訪問指定IP即可訪問
    [root@node1 ~]# curl -I -s  10.244.2.2 |grep 200
    HTTP/1.1 200 OK
    

    部署CoreDNS

    CoreDNS用於集群內部Service名稱解析

    kubectl apply -f coredns.yaml 
    serviceaccount/coredns created
    clusterrole.rbac.authorization.k8s.io/system:coredns created
    clusterrolebinding.rbac.authorization.k8s.io/system:coredns 
    configmap/coredns created
    deployment.apps/coredns created
    
    DNS解析測試
    kubectl run -it --rm dns-test --image=busybox:1.28.4 sh
    If you don't see a command prompt, try pressing enter.
    / # nslookup kubernetes
    Server:    10.0.0.2
    Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
    
    Name:      kubernetes
    Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
    

    此篇文章借鑒於公眾號DevOps技術棧 ,作者阿良

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

    【其他文章推薦】

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

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

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

    ※超省錢租車方案

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

  • jvm入門及理解(六)——垃圾回收與算法

    jvm入門及理解(六)——垃圾回收與算法

    一、jvm垃圾回收要做的事情

    • 哪些內存需要回收
    • 什麼時候回收
    • 怎麼回收

    二、如何判斷對象已經死亡,或者說確定為垃圾

    1. 引用計數法:

      給對象中添加一個引用計數器,每當有一個地方引用它時,計數器的值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的。這也就是需要回收的對象,簡單地說,即一個對象如果沒有任何與之關聯的引用,即他們的引用計數都為 0,則說明對象不太可能再被用到,那麼這個對象就是可回收的對象。

      引用計數法是對象記錄自己被多少程序引用,引用計數為零的對象將被清除。

      計數器表示的是有多少程序引用了這個對象(被引用數)。計數器是無符號的整數。

    2. 根搜索算法:

        通過一系列成為GC roots的點作為起點,向下搜索,當一個對象到任何GC Roots時沒有引用鏈相連,則說明對象已經死亡。

        如果在GC roots和一個對象之間沒有可達路徑(引用鏈),則稱該對象是不可達的。要注意的是,不可達對象不等價於可回收對象,不可達對象變為可回收對象至少要經過兩次標記 過程。兩次標記后仍然是可回收對象,則將面臨回收。

        jvm會將以下的對象定義為GC Roots:

     

    • Java虛擬機棧中引用的對象:比如方法裏面定義這種局部變量 User user= new User();
    • 方法區中的靜態屬性引用的對象:比如 private static User user = new User();
    • 常量引用的對象:比如 private static final  User user = new User();
    • 本地方法棧(JNI)中引用的對象

    三、垃圾回收算法

    1. 標記清除算法(Mark-Sweep)

        是最基礎的垃圾回收算法,分為兩個階段,標註和清除。標記階段標記出所有需要回收的對象,清除階段回收被標記的對象所佔用的空間。首先從根開始將可能被引用的對象用遞歸的方式進行標記,然後將沒有標記到的對象作為垃圾進行回收。

     

     

    從圖中我們就可以發現,該算法最大的問題是內存碎片化嚴重,後續可能發生大對象不能找到可利用空間的問題。

     

     

      2. 複製算法(copying)

       為了解決 Mark-Sweep 算法內存碎片化的缺陷而被提出的算法。按內存容量將內存劃分為等大小 的兩塊。每次只使用其中一塊,當這一塊內存滿后將尚存活的對象複製到另一塊上去,把已使用 的內存清掉,如圖:

     

     

     

     

     

     這種算法雖然實現簡單,內存效率高,不易產生碎片,但是最大的問題是可用內存被壓縮到了原 本的一半。且存活對象增多的話,Copying 算法的效率會大大降低。

      

      3.標記整理算法(Mark-Compact)

       結合了以上兩個算法,為了避免缺陷而提出。標記階段和 Mark-Sweep 算法相同,標記后不是清 理對象,而是將存活對象移向內存的一端。然後清除端邊界外的對象。如圖:

     

     

     

    四、分代收集算法

      介紹:分代收集法是目前大部分 JVM 所採用的方法,其核心思想是根據對象存活的不同生命周期將內存 劃分為不同的域,一般情況下將 GC 堆劃分為老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特點是每次垃圾回收時只有少量對象需要被回收,新生代的特點是每次垃圾回收時都有大量垃圾需要被回收,因此可以根據不同區域選擇不同的算法。

    1. 新生代與複製算法

        目前大部分 JVM 的 GC 對於新生代都採取 Copying 算法,因為新生代中每次垃圾回收都要 回收大部分對象,即要複製的操作比較少,但通常並不是按照 1:1 來劃分新生代。一般將新生代 劃分為一塊較大的 Eden 空間和兩個較小的 Surviror 空間(From Space, To Space),每次使用 Eden 空間和其中的一塊 Survivor 空間,當進行回收時,將該兩塊空間中還存活的對象複製到另 一塊 Survivor 空間中。

      

     

     

     假設from space為s0,to space 為s1

    算法過程:

    1. Eden+S0可分配新生對象;
    2. 對Eden+S0進行垃圾收集,存活對象複製到S1清理Eden+S0。一次新生代GC結束。
    3. Eden+S1可分配新生對象;
    4. 對Eden+S1進行垃圾收集,存活對象複製到S0清理Eden+S1。二次新生代GC結束。
    5. 循環1。

      2.老年代與標記整理算法

    老年代因為每次只回收少量對象,因而採用 Mark-Compact 算法。

    1. JAVA 虛擬機提到過的處於方法區的永生代(Permanet Generation),它用來存儲 class 類, 常量,方法描述等。對永生代的回收主要包括廢棄常量和無用的類。

    2. 對象的內存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目 前存放對象的那一塊),少數情況會直接分配到老生代。

    3. 當新生代的 Eden Space 和 From Space 空間不足時就會發生一次 GC,進行 GC 后,Eden Space 和 From Space 區的存活對象會被挪到 To Space,然後將 Eden Space 和 From Space 進行清理。

    4. 如果 To Space 無法足夠存儲某個對象,則將這個對象存儲到老生代。

    5. 在進行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反覆循環。

    6. 當對象在 Survivor 區躲過一次 GC 后,其年齡就會+1。默認情況下年齡到達 15 的對象會被 移到老生代中。

     

    五、分區收集算法

    分區算法則將整個堆空間劃分為連續的不同小區間, 每個小區間獨立使用, 獨立回收. 這樣做的 好處是可以控制一次回收多少個小區間 , 根據目標停頓時間, 每次合理地回收若干個小區間(而不是 整個堆), 從而減少一次 GC 所產生的停頓。

     

    六、java中的四種引用

    • 強引用

    在 Java 中最常見的就是強引用,把一個對象賦給一個引用變量,這個引用變量就是一個強引 用。當一個對象被強引用變量引用時,它處於可達狀態,它是不可能被垃圾回收機制回收的,即 使該對象以後永遠都不會被用到 JVM 也不會回收。因此強引用是造成 Java 內存泄漏的主要原因之一,直接new的對象就是強引用的。

    • 軟引用

    軟引用需要用 SoftReference 類來實現,對於只有軟引用的對象來說,當系統內存足夠時它 不會被回收,當系統內存空間不足時它會被回收。軟引用通常用在對內存敏感的程序中。

    • 弱引用

    弱引用需要用 WeakReference 類來實現,它比軟引用的生存期更短,對於只有弱引用的對象 來說,只要垃圾回收機制一運行,不管 JVM 的內存空間是否足夠,總會回收該對象佔用的內存。

    • 虛引用

    虛引用需要 PhantomReference 類來實現,它不能單獨使用,必須和引用隊列聯合使用。虛 引用的主要作用是跟蹤對象被垃圾回收的狀態。

     

    七、GC 垃圾收集器

    Java 堆內存被劃分為新生代和年老代兩部分,新生代主要使用複製和標記-清除垃圾回收算法; 年老代主要使用標記-整理垃圾回收算法,因此 java 虛擬中針對新生代和年老代分別提供了多種不 同的垃圾收集器,JDK1.6 中 Sun HotSpot 虛擬機的垃圾收集器如下:

     

    新生代:

    1.  Serial 垃圾收集器(單線程、複製算法)

    Serial(英文連續)是最基本垃圾收集器,使用複製算法,曾經是JDK1.3.1 之前新生代唯一的垃圾 收集器。Serial 是一個單線程的收集器,它不但只會使用一個 CPU 或一條線程去完成垃圾收集工 作,並且在進行垃圾收集的同時,必須暫停其他所有的工作線程,直到垃圾收集結束。 Serial 垃圾收集器雖然在收集垃圾過程中需要暫停所有其他的工作線程,但是它簡單高效,對於限 定單個 CPU 環境來說,沒有線程交互的開銷,可以獲得最高的單線程垃圾收集效率,因此 Serial 垃圾收集器依然是 java 虛擬機運行在 Client 模式下默認的新生代垃圾收集器。

       2.ParNew 垃圾收集器(Serial+多線程)

    ParNew 垃圾收集器其實是 Serial 收集器的多線程版本,也使用複製算法,除了使用多線程進行垃 圾收集之外,其餘的行為和 Serial 收集器完全一樣,ParNew 垃圾收集器在垃圾收集過程中同樣也 要暫停所有其他的工作線程。 ParNew 收集器默認開啟和 CPU 數目相同的線程數,可以通過-XX:ParallelGCThreads 參數來限 制垃圾收集器的線程數。ParNew雖然是除了多線程外和Serial 收集器幾乎完全一樣,但是ParNew垃圾收集器是很多 java 虛擬機運行在 Server 模式下新生代的默認垃圾收集器。

      3.Parallel Scavenge 收集器(多線程複製算法、高效)

    Parallel Scavenge 收集器也是一個新生代垃圾收集器,同樣使用複製算法,也是一個多線程的垃 圾收集器,它重點關注的是程序達到一個可控制的吞吐量(Thoughput,CPU 用於運行用戶代碼 的時間/CPU 總消耗時間,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)), 高吞吐量可以最高效率地利用 CPU 時間,儘快地完成程序的運算任務,主要適用於在後台運算而 不需要太多交互的任務。自適應調節策略也是 ParallelScavenge 收集器與 ParNew 收集器的一個 重要區別。

     

    老年代:

      4.Serial Old 收集器(單線程標記整理算法 )

    Serial Old 是 Serial 垃圾收集器年老代版本,它同樣是個單線程的收集器,使用標記-整理算法, 這個收集器也主要是運行在 Client 默認的 java 虛擬機默認的年老代垃圾收集器。 在 Server 模式下,主要有兩個用途:

        1. 在 JDK1.5 之前版本中與新生代的 Parallel Scavenge 收集器搭配使用。

        2. 作為年老代中使用 CMS 收集器的後備垃圾收集方案。

    新生代 Parallel Scavenge 收集器與 ParNew 收集器工作原理類似,都是多線程的收集器,都使 用的是複製算法,在垃圾收集過程中都需要暫停所有的工作線程。

      

      5.Parallel Old 收集器(多線程標記整理算法)

    Parallel Old 收集器是Parallel Scavenge的年老代版本,使用多線程的標記-整理算法,在 JDK1.6 才開始提供。 在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只 能保證新生代的吞吐量優先,無法保證整體的吞吐量,Parallel Old 正是為了在年老代同樣提供吞 吐量優先的垃圾收集器,如果系統對吞吐量要求比較高,可以優先考慮新生代 Parallel Scavenge 和年老代 Parallel Old 收集器的搭配策略。

     

      6.Parallel Old 收集器(多線程標記整理算法)

    Parallel Old 收集器是Parallel Scavenge的年老代版本,使用多線程的標記-整理算法,在 JDK1.6 才開始提供。 在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只 能保證新生代的吞吐量優先,無法保證整體的吞吐量,Parallel Old 正是為了在年老代同樣提供吞 吐量優先的垃圾收集器,如果系統對吞吐量要求比較高,可以優先考慮新生代 Parallel Scavenge 和年老代 Parallel Old 收集器的搭配策略。

      

      7.CMS 收集器(多線程標記清除算法)

    Concurrent mark sweep(CMS)收集器是一種年老代垃圾收集器,其最主要目標是獲取最短垃圾 回收停頓時間,和其他年老代使用標記-整理算法不同,它使用多線程的標記-清除算法。 最短的垃圾收集停頓時間可以為交互比較高的程序提高用戶體驗。

     

     

      8.G1 收集器

    Garbage first 垃圾收集器是目前垃圾收集器理論發展的最前沿成果,相比與 CMS 收集器,G1 收 集器兩個最突出的改進是:

        1. 基於標記-整理算法,不產生內存碎片。

        2. 可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。 G1 收集器避免全區域垃圾收集,它把堆內存劃分為大小固定的幾個獨立區域,並且跟蹤這些區域 的垃圾收集進度,同時在後台維護一個優先級列表,每次根據所允許的收集時間,優先回收垃圾 最多的區域。區域劃分和優先級區域回收機制,確保 G1 收集器可以在有限時間獲得最高的垃圾收 集效率。

     

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

  • 【Spring】@Transactional 閑聊

    菜瓜:上次的AOP理論知識看完收穫挺多的,雖然有一個自定義註解的demo,但還是覺得差點東西

    水稻:我也覺得沒有跟一遍源碼還是差點意思,這次結合@Transactional註解深入源碼看一下

    菜瓜:事務註解,這個平時用的挺多的

    水稻:是嗎?來看看你的基礎咋樣

    1. 要保證一個方法中多個數據庫操作的原子性,要共用一個數據庫連接,但是coding時我們不用显示傳遞連接對象,這是咋弄的?
    2. 如果一個方法裏面只有查詢操作,是否不用開啟事務?
    3. 如何解決非事務方法調用本地事務方法失效的?
    4. 註解常用的傳播屬性,你知道他們的區別嗎

    菜瓜:雖然沒看過源碼,我大膽猜測一下

    1. 隱式傳遞連接對象可以將其封裝到線程中,一般一次請求操作都是在一個線程中完成。使用ThreadLocal將連接和線程綁定
    2. 查詢操作也得看業務場景,如果多次查詢相同的數據要避免不可重複讀問題,可開啟只讀事務 (readOnly = true)
    3. 結合AOP的知識,這裏其實要解決調用事務方法的對象不是代理對象的問題。用代理對象調本地事務方法即可(注入自己)
      • /**
         * @author QuCheng on 2020/6/24.
         */
        @Service
        public class ItemServiceImpl implements ItemService {
        
            @Resource
            private IcbcItemMapper itemMapper;
        
            @Resource
            private ItemService itemService;
        
            @Override
            public void changeNameById(Long itemId) {
                // changeItemById(itemId);
                itemService.changeItemById(itemId);
            }
        
            @Transactional(rollbackFor = RuntimeException.class)
            @Override
            public void changeItemById(Long itemId) {
                itemMapper.updateNameById(itemId, "name4");
                int a = 10 / 0;
                itemMapper.updatePriceById(itemId, 100L);
            }
        }
    4. 傳播屬性這個沒了解過啊,數據庫事務裏面么得這個概念

    水稻:可以啊,平時的代碼沒白寫

    菜瓜:coding這種事情,easy啦!

    水稻:這就飄了?來看這個問題

    • 如果我想在A事務方法中調用B事務方法,B方法如果回滾了,不能影響A事務繼續執行,但是A事務如果執行出問題了,B也要回滾,怎麼弄?

    菜瓜:。。。這不就是大事務嵌套小事務嘛。。。我不會

    水稻:不扯了,來看源碼吧,這個問題等解釋了傳播屬性你就知道了

    • 上回我們說到,@Transactional是AOP的典型應用,bean被實例化之後要創建代理(參考自定義註解),就少不了切面類Advisor對象。那麼它是誰,它在哪,它在干什麼?
    • 回到夢開始的地方,事務功能開啟的註解@EnableTransactionManagement
      • 沒錯,它肯定會有一個Import註解引入TransactionManagementConfigurationSelector類,它又引入了切面類
      • public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
         
           @Override
           protected String[] selectImports(AdviceMode adviceMode) {
              switch (adviceMode) {
                 case PROXY:
                    return new String[] {AutoProxyRegistrar.class.getName(),
                          // 看這裏
                          ProxyTransactionManagementConfiguration.class.getName()};
                 case ASPECTJ:
                    return new String[] {determineTransactionAspectClass()};
                 default:
                    return null;
              }
           }
        。。。
        
        }
        
        
        @Configuration
        public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
        
           @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
           @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
           public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
              BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
              advisor.setTransactionAttributeSource(transactionAttributeSource());
              advisor.setAdvice(transactionInterceptor());
              if (this.enableTx != null) {
                 advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
              }
              return advisor;
           }
        
           @Bean
           @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
           public TransactionAttributeSource transactionAttributeSource() {
              return new AnnotationTransactionAttributeSource();
           }
        
           @Bean
           @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
           public TransactionInterceptor transactionInterceptor() {
        // 增強 TransactionInterceptor interceptor
        = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } } 
      • 切面類對象設置了事務的掃描器,也set了增強類TransactionInterceptor
      • public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
        。。。
        @Override
            @Nullable
            public Object invoke(MethodInvocation invocation) throws Throwable {
                // Work out the target class: may be {@code null}.
                // The TransactionAttributeSource should be passed the target class
                // as well as the method, which may be from an interface.
                Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        
                // Adapt to TransactionAspectSupport's invokeWithinTransaction...
                return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
            }
        }
        
        public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
          
        。。。  
        @Nullable
        protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
              final InvocationCallback invocation) throws Throwable {
           。。。
        // ①創建事務,數據庫連接處理也在這 TransactionInfo txInfo
        = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try {
        // 調用目標方法 retVal
        = invocation.proceedWithInvocation(); } catch (Throwable ex) {
        // 異常後事務處理 completeTransactionAfterThrowing(txInfo, ex);
        throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; } 。。。 } 

    菜瓜:懂,接下來的代碼邏輯就是在增強類TransactionInterceptor的invoke方法里

    水稻:對

    • 先看數據庫連接的處理 – 驗證ThreadLocal
    • protected void doBegin(Object transaction, TransactionDefinition definition) {
         。。。
      // 如果連接是新的,就進行綁定
      if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder()); } 。。。 } class TransactionSynchronizationManager public static void bindResource(Object key, Object value) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Assert.notNull(value, "Value must not be null"); Map<Object, Object> map = resources.get(); // set ThreadLocal Map if none found if (map == null) { map = new HashMap<>(); resources.set(map); } Object oldValue = map.put(actualKey, value); // Transparently suppress a ResourceHolder that was marked as void... if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) { oldValue = null; } if (oldValue != null) { throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } if (logger.isTraceEnabled()) { logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]"); } }
    • 回過頭來看AB方法調用的回滾問題,直接給出答案(突然發現這個問題要講清楚篇幅會很大,就。。挺突然的。。挺突然der)
      • 在B方法上設置傳播屬性為NESTED即可,然後在A中catch住B的異常
      • 你肯定會問我不加NESTED去catch不行嗎?不行,非NESTED的方法拋出的異常是無法回滾的。
      • 不信你看
      • @Transactional(rollbackFor = RuntimeException.class)
            @Override
            public void changeNameById(Long itemId) {
                itemMapper.updateNameById(itemId, "A");
                try {
                    itemService.changeItemById(itemId);
        //            itemService.changeItemByIdNested(itemId);
                } catch (Exception e) {
                    System.out.println("我想繼續執行,不影響修改A");
                }
                itemMapper.updatePriceById(itemId, 1L);
            }
        
            @Transactional(rollbackFor = RuntimeException.class)
            @Override
            public void changeItemById(Long itemId) {
                itemMapper.updateNameById(itemId, "B+REQUIRED");
                itemMapper.updatePriceById(itemId, 10L);
                int a = 10 / 0;
            }
        
            @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.NESTED)
            @Override
            public void changeItemByIdNested(Long itemId) {
                itemMapper.updateNameById(itemId, "B+NESTED");
                itemMapper.updatePriceById(itemId, 100L);
                int a = 10 / 0;
            }
        
        
        -- 測試結果
        //①  itemService.changeItemById(itemId);  數據庫所有數據都不會改變
        我想繼續執行,不影響修改A
        org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
        
        // ② itemService.changeItemByIdNested(itemId); 第一個方法的修改會生效
        我想繼續執行,不影響修改A

    菜瓜:這就是傳播屬性NESTED?默認的是REQUIRED,還有一個常用的REQUIRES_NEW呢?

    水稻:搞清楚這個其實從數據庫連接入手其實就很清楚

    • REQUIRED修飾的方法和A使用同一個連接,A和B是掛一起的,誰回滾都會影響對方,且B方法的異常會被事務管理器標記為必須回滾
    • NESTED修飾的方法和A使用同一個連接,但是用到了數據庫的savePoint特性,它可以回滾到指定的點,如果是有回滾點的操作,拋出的異常可以被處理
    • REQUIRES_NEW修飾的方法和A使用的就不是一個連接了,回不回滾都不會影響對方,當然,要捕捉異常

    菜瓜:傳播屬性了解。回滾的問題還得再看看,篇幅很大是很複雜嗎?

    水稻:其實不複雜,就是要跟蹤源碼斷點調試。。。截圖搞來搞去,篇幅就很長,你自己去調的話其實很快

    菜瓜:那我下去康康

     

    總結

    • 這裏提到Transactional註解其實是為了鞏固AOP的,當然提到了一些注意點。譬如本地調用,譬如ThreadLocal的應用,還譬如傳播屬性
    • 傳播屬性其實用的少,但是聊起來就比較多了,可以聊事務的隔離級別,聊ACID的實現,聊MySQL的鎖

     

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

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

  • 中國政策放開電動車准入要求 小米或入局電動車

    中國政策放開電動車准入要求 小米或入局電動車

    11月26日,國家發改委網站掛出《新建純電動乘用車生企業投資項目和生產準入管理的暫行規定(徵求意見稿)》(以下簡稱《規定》),計劃為純電動車生準入放開口子。   《規定》要求的三條基礎能力中,最核心的是:(申報企業)有3年以上純電動乘用車的研發基礎,具有專業研發團隊和整車正向研發能力,掌握整車控制系統、動力電池系統、整車整合和整車輕量化方面的核心技術以及相應的試驗驗證能力,擁有純電動乘用車自主智慧財產權和已授權的相關發明專利。另外還要求新建企業只能生產純電動轎車和純電動其他乘用車(包括增程式電動乘用車),插電式混合動力不在準入範圍內。   面對新一批電動車開放名單,包括小米、樂視與萬向等企業集團都展現出高度興趣,爭取成為入圍名單。其中小米的動向最受矚目。小米創辦人之一黎萬強早在10月底就悄悄飛往矽谷展開暖身動作,小米董事長雷軍更在拜會特斯拉後就對電動車念念不忘。事實上,小米電動車的諜照早就在網路上曝光,只是細節外界所知不多。不過,這次開放的限制很嚴,小米能否如願以償擠進電動車窄門,備受關注。   (照片來源: )

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 中國官方將 2014 訂為電動車市場元年 預估 2020 年達 500 萬輛

    永豐投顧研調處表示,目前全球電動車的滲透率不到 0.3%,預估 2017 年將突破百萬輛,其中,中國大陸設定 2020 年要達到 500 萬輛電動車的市場規模。   根據大陸中央政府推出的優惠補貼政策,2014 年 9 月推出電動車免徵購置稅的優惠,且示範城市地方政府提供的補貼金額往往與中央政府相當,而在北京、上海及廣東等限牌都市,新能源車可直接上牌,對民眾及車廠而言也是一大誘因。   大陸官方甚至將 2014 年稱為大陸電動車市場化元年,從銷售量來看,這樣的稱號一點也不為過,從 2013 年不到 2 萬輛的銷售量到 2014 年預估可望突破 6 萬輛,短短時間內,電動車市場銷售大爆發。

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

    【其他文章推薦】

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

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

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

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

    ※超省錢租車方案

  • 北汽正研發8款新能源車 未來兩年陸續推出

    日前,北汽新能源車在未來兩年內的整體規劃曝光,其目前正在研發的車型有4款,策劃車型3款,預研車型1款,規劃車型1款,共計8款新能源車型,涵蓋了大、中、小系列產品規劃。   據悉,代號為C30DB、C33DB、C70GB和M30RB等四款正在研發的車型主要是針對現產品的技術改進,改進方向為制動能量回收技術、輕量化和智慧化等三大方面。如磷酸鐵鋰電池容量由60毫安培提升至80毫安培,整車續航里程提升至200公里。安全方面,新型動力電池實現IP67防護等級,並大量應用輕量化技術應用,動力電池箱蓋體則減重品質20公斤,減重率超過30%。   此外,代號為C10IB、C50EB、C71GB等三款車型為新產品開發,其中C10IB為微型車,C50EB為緊湊型車,而C71GB為中型車,這三款車型有望在2015年面向市場。而代號為C80GB的中大型車則計畫2016年面向市場。

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

    【其他文章推薦】

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

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

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

    ※超省錢租車方案