DevOps實踐

Jas0n0ss發表於2024-08-04

DevOps

一、DevOps介紹

軟體開發最開始是由兩個團隊組成:

  • 開發計劃由開發團隊從頭開始設計和整體系統的構建。需要系統不停的迭代更新。
  • 運維團隊將開發團隊的Code進行測試後部署上線。希望系統穩定安全執行。

這看似兩個目標不同的團隊需要協同完成一個軟體的開發。

在開發團隊指定好計劃並完成coding後,需要提供到運維團隊。

運維團隊向開發團隊反饋需要修復的BUG以及一些需要返工的任務。

這時開發團隊需要經常等待運維團隊的反饋。這無疑延長了事件並推遲了整個軟體開發的週期。

會有一種方式,在開發團隊等待的時候,讓開發團隊轉移到下一個專案中。等待運維團隊為之前的程式碼提供反饋。

可是這樣就意味著一個完整的專案需要一個更長的週期才可以開發出最終程式碼。


基於現在的網際網路現狀,更推崇敏捷式開發,這樣就導致專案的迭代速度更快,但是由於開發團隊與運維團隊的溝通問題,會導致新版本上線的時間成本很高。這又違背的敏捷式開發的最初的目的。

那麼如果讓開發團隊和運維團隊整合到成一個團隊,協同應對一套軟體呢?這就被稱為DevOps

DevOps,字面意思是Development &Operations的縮寫,也就是開發&運維。

雖然字面意思只涉及到了開發團隊和運維團隊,其實QA測試團隊也是參與其中的。

網上可以檢視到DevOps的符號類似於一個無窮大的符號

DevOps
image-20211124130409521

這表明DevOps是一個不斷提高效率並且持續不斷工作的過程

DevOps的方式可以讓公司能夠更快地應對更新和市場發展變化,開發可以快速交付,部署也更加穩定。

核心就在於簡化Dev和Ops團隊之間的流程,使整體軟體開發過程更快速。

整體的軟體開發流程包括:

  • PLAN:開發團隊根據客戶的目標制定開發計劃
  • CODE:根據PLAN開始編碼過程,需要將不同版本的程式碼儲存在一個庫中。
  • BUILD:編碼完成後,需要將程式碼構建並且執行。
  • TEST:成功構建專案後,需要測試程式碼是否存在BUG或錯誤。
  • DEPLOY:程式碼經過手動測試和自動化測試後,認定程式碼已經準備好部署並且交給運維團隊。
  • OPERATE:運維團隊將程式碼部署到生產環境中。
  • MONITOR:專案部署上線後,需要持續的監控產品。
  • INTEGRATE:然後將監控階段收到的反饋傳送回PLAN階段,整體反覆的流程就是DevOps的核心,即持續整合、持續部署。

為了保證整體流程可以高效的完成,各個階段都有比較常見的工具,如下圖:

軟體開發過程&涉及工具
2021-11-23_175935

最終可以給DevOps下一個定義:DevOps 強調的是高效組織團隊之間如何透過自動化的工具協作和溝通來完成軟體的生命週期管理,從而更快、更頻繁地交付更穩定的軟體。

自動化的工具協作和溝通來完成軟體的生命週期管理

二、Code階段工具

在code階段,我們需要將不同版本的程式碼儲存到一個倉庫中,常見的版本控制工具就是SVN或者Git,這裡我們採用Git作為版本控制工具,GitLab作為遠端倉庫。

2.1 Git安裝

https://git-scm.com/(傻瓜式安裝)

2.2 GitLab安裝

單獨準備伺服器,採用Docker安裝

  • 檢視GitLab映象

    docker search gitlab
    
  • 拉取GitLab映象

    docker pull gitlab/gitlab-ce
    
  • 準備docker-compose.yml檔案

    version: '3.1'
    services:
      gitlab:
        image: 'gitlab/gitlab-ce:latest'
        container_name: gitlab
        restart: always
        environment:
          GITLAB_OMNIBUS_CONFIG: |
            external_url 'http://192.168.11.11:8929'
            gitlab_rails['gitlab_shell_ssh_port'] = 2224
        ports:
          - '8929:8929'
          - '2224:2224'
        volumes:
          - './config:/etc/gitlab'
          - './logs:/var/log/gitlab'
          - './data:/var/opt/gitlab'
    
  • 啟動容器(需要稍等一小會……)

    docker-compose up -d
    
  • 訪問GitLab首頁

    首頁
    image-20211124182140596
  • 檢視root使用者初始密碼

    docker exec -it gitlab cat /etc/gitlab/initial_root_password
    
    初始密碼
    image-20211124182921234
  • 登入root使用者

    登入成功後跳轉頁面
    image-20211124183003858
  • 第一次登入後需要修改密碼

    修改密碼
    image-20211124193444561

搞定後,即可像Gitee、GitHub一樣使用。

三、Build階段工具

構建Java專案的工具一般有兩種選擇,一個是Maven,一個是Gradle。

這裡我們選擇Maven作為專案的編譯工具。

具體安裝Maven流程不做闡述,但是需要確保配置好Maven倉庫私服以及JDK編譯版本。

四、Operate階段工具

部署過程,會採用Docker進行部署,暫時只安裝Docker即可,後續還需安裝Kubenetes

4.1 Docker安裝

  • 準備測試環境&生產環境

  • 下載Docker依賴元件

    yum -y install yum-utils device-mapper-persistent-data lvm2
    
  • 設定下載Docker的映象源為阿里雲

    yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
  • 安裝Docker服務

    yum -y install docker-ce
    
  • 安裝成功後,啟動Docker並設定開機自啟

    # 啟動Docker服務
    systemctl start docker
    # 設定開機自動啟動
    systemctl enable docker
    
  • 測試安裝成功

    docker version
    
    效果
    image-20211124200317795

4.2 Docker-Compose安裝

  • 下載Docker/Compose:https://github.com/docker/compose

  • 將下載好的docker-compose-Linux-x86_64檔案移動到Linux作業系統:……

  • 設定docker-compose-Linux-x86_64檔案許可權,並移動到$PATH目錄中

    # 設定檔案許可權
    chmod a+x docker-compose-Linux-x86_64
    # 移動到/usr/bin目錄下,並重新命名為docker-compose
    mv docker-compose-Linux-x86_64 /usr/bin/docker-compose
    
  • 測試安裝成功

    docker-compose version
    
    效果
    image-20211124200658107

五、Integrate工具

持續整合、持續部署的工具很多,其中Jenkins是一個開源的持續整合平臺。

Jenkins涉及到將編寫完畢的程式碼釋出到測試環境和生產環境的任務,並且還涉及到了構建專案等任務。

Jenkins需要大量的外掛保證工作,安裝成本較高,下面會基於Docker搭建Jenkins。

5.1 Jenkins介紹

Jenkins是一個開源軟體專案,是基於Java開發的一種持續整合工具

Jenkins應用廣泛,大多數網際網路公司都採用Jenkins配合GitLab、Docker、K8s作為實現DevOps的核心工具。

Jenkins最強大的就在於外掛,Jenkins官方提供了大量的外掛庫,來自動化CI/CD過程中的各種瑣碎功能。

image-20211125141950900 image-20211124200317795

Jenkins最主要的工作就是將GitLab上可以構建的工程程式碼拉取並且進行構建,再根據流程可以選擇釋出到測試環境或是生產環境。

一般是GitLab上的程式碼經過大量的測試後,確定發行版本,再發布到生產環境。

CI/CD可以理解為:

  • CI過程即是透過Jenkins將程式碼拉取、構建、製作映象交給測試人員測試。
    • 持續整合:讓軟體程式碼可以持續的整合到主幹上,並自動構建和測試。
  • CD過程即是透過Jenkins將打好標籤的發行版本程式碼拉取、構建、製作映象交給運維人員部署。
    • 持續交付:讓經過持續整合的程式碼可以進行手動部署。
    • 持續部署:讓可以持續交付的程式碼隨時隨地的自動化部署。
CI、CD
image-20211125154112097

5.2 Jenkins安裝

  • 拉取Jenkins映象

    docker pull jenkins/jenkins
    
  • 編寫docker-compose.yml

    version: "3.1"
    services:
      jenkins:
        image: jenkins/jenkins
        container_name: jenkins
        ports:
          - 8080:8080
          - 50000:50000
        volumes:
          - ./data/:/var/jenkins_home/
    
  • 首次啟動會因為資料卷data目錄沒有許可權導致啟動失敗,設定data目錄寫許可權

    錯誤日誌
    image-20211124202610243
    chmod -R a+w data/
    
  • 重新啟動Jenkins容器後,由於Jenkins需要下載大量內容,但是由於預設下載地址下載速度較慢,需要重新設定下載地址為國內映象站

    # 修改資料卷中的hudson.model.UpdateCenter.xml檔案
    <?xml version='1.1' encoding='UTF-8'?>
    <sites>
      <site>
        <id>default</id>
        <url>https://updates.jenkins.io/update-center.json</url>
      </site>
    </sites>
    # 將下載地址替換為http://mirror.esuni.jp/jenkins/updates/update-center.json
    <?xml version='1.1' encoding='UTF-8'?>
    <sites>
      <site>
        <id>default</id>
        <url>http://mirror.esuni.jp/jenkins/updates/update-center.json</url>
      </site>
    </sites>
    # 清華大學的外掛源也可以https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
    
  • 再次重啟Jenkins容器,訪問Jenkins(需要稍微等會)

    Jenkins首頁
    image-20211124204517433
    image-20211124203336300
  • 檢視密碼登入Jenkins,並登入下載外掛

    docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword
    
    登入並下載外掛
    image-20211124205050484
    image-20211124205513465
  • 選擇需要安裝的外掛

    選擇需要安裝的外掛
    image-20211124205854418
    image-20211124205858730
    image-20211124205917317
  • 下載完畢設定資訊進入首頁(可能會出現下載失敗的外掛)

    image-20211124211635550
    image-20211124211700999
    image-20211124211720836

5.3 Jenkins入門配置

由於Jenkins需要從Git拉取程式碼、需要本地構建、甚至需要直接釋出自定義映象到Docker倉庫,所以Jenkins需要配置大量內容。

5.3.1 構建任務

準備好GitLab倉庫中的專案,並且透過Jenkins配置專案的實現當前專案的DevOps基本流程。

  • 構建Maven工程釋出到GitLab(Gitee、Github均可)

    GitLab檢視專案
    image-20211125195818670
  • Jenkins點選左側導航新建任務

    新建任務
    image-20211125163541645
  • 選擇自由風格構建任務

    構建任務
    image-20211125170350811
5.3.1 配置原始碼拉取地址

Jenkins需要將Git上存放的原始碼儲存到Jenkins服務所在磁碟的本地

  • 配置任務原始碼拉取的地址

    原始碼管理
    image-20211125170418337
  • Jenkins立即構建

    點選任務test中的立即構建
    image-20211125200218093
  • 檢視構建工程的日誌,點選上述③的任務條即可

    檢視任務拉取Git原始碼日誌
    image-20211125201701443

    可以看到原始碼已經拉取帶Jenkins本地,可以根據第三行日誌資訊,檢視Jenkins本地拉取到的原始碼。

  • 檢視Jenkins容器中/var/jenkins_home/workspace/test的原始碼

    原始碼存放位置
    image-20211125201919108
5.3.2 配置Maven構建程式碼

程式碼拉取到Jenkins本地後,需要在Jenkins中對程式碼進行構建,這裡需要Maven的環境,而Maven需要Java的環境,接下來需要在Jenkins中安裝JDK和Maven,並且配置到Jenkins服務。

  • 準備JDK、Maven壓縮包透過資料卷對映到Jenkins容器內部

    資料卷存放位置
    image-20211125203757232
  • 解壓壓縮包,並配置Maven的settings.xml

    <!-- 阿里雲映象地址 -->
    <mirror>  
        <id>alimaven</id>  
        <name>aliyun maven</name>  
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <mirrorOf>central</mirrorOf>          
    </mirror>
    <!-- JDK1.8編譯外掛 -->
    <profile>
        <id>jdk-1.8</id>
        <activation>
            <activeByDefault>true</activeByDefault>
            <jdk>1.8</jdk>
        </activation>
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        </properties>        
    </profile>
    
  • Jenkins配置JDK&Maven並儲存

    image-20211125204811759
    image-20211125204818869
  • 配置Jenkins任務構建程式碼

    配置Maven構建程式碼
    image-20211125205027013
    image-20211125205020738
  • 立即構建測試,檢視target下的jar包

    構建原始碼
    image-20211125205240208
    image-20211125205725948
5.3.3 配置Publish釋出&遠端操作

jar包構建好之後,就可以根據情況釋出到測試或生產環境,這裡需要用到之前下載好的外掛Publish Over SSH。

  • 配置Publish Over SSH連線測試、生產環境

    Publish Over SSH配置
    image-20211125210148202
  • 配置任務的構建後操作,釋出jar包到目標服務

    配置構建後操作
    image-20211125205027013
    image-20211125210424346
    image-20211125210626631
  • 立即構建任務,並去目標服務檢視

    立即構建
    image-20211125210755556
    image-20211125210826057

六、CI、CD入門操作

基於Jenkins拉取GitLab的SpringBoot程式碼進行構建釋出到測試環境實現持續整合

基於Jenkins拉取GitLab指定發行版本的SpringBoot程式碼進行構建釋出到生產環境實現CD實現持續部署

6.1 持續整合

為了讓程式程式碼可以自動推送到測試環境基於Docker服務執行,需要新增Docker配置和指令碼檔案讓程式可以在整合到主幹的同時執行起來。

  • 新增Dockerfile檔案

    構建自定義映象
    image-20211126161304485
  • 新增docker-compose.yml檔案

    載入自定義映象啟動容器
    image-20211126161331991
  • 追加Jenkins構建後操作指令碼命令

    構建後釋出並執行指令碼命令
    image-20211126161408514
  • 釋出到GitLab後由Jenkins立即構建並託送到目標伺服器

    構建日誌
    image-20211126161448527
  • 測試部署到目標伺服器程式

    檢視目標伺服器並測試介面
    image-20211126161504715
    image-20211126161509411

6.2 持續交付、部署

程式程式碼在經過多次整合操作到達最終可以交付,持續交付整體流程和持續整合類似,不過需要選取指定的發行版本

  • 下載Git Parameter外掛

    下載Git Parameter
    image-20211126165209057
  • 設定專案引數化構建

    基於Git標籤構建
    image-20211126165444124
    image-20211126172828266
  • 給專案新增tag版本

    新增tag版本
    image-20211126165639286
  • 任務構建時,採用Shell方式構建,拉取指定tag版本程式碼

    切換指定標籤並構建專案
    image-20211126174715028
  • 基於Parameter構建任務,任務釋出到目標伺服器

    構建任務
    image-20211126174159487

七、整合Sonar Qube

7.1 Sonar Qube介紹

Sonar Qube是一個開源的程式碼分析平臺,支援Java、Python、PHP、JavaScript、CSS等25種以上的語言,可以檢測出重複程式碼、程式碼漏洞、程式碼規範和安全性漏洞的問題。

Sonar Qube可以與多種軟體整合進行程式碼掃描,比如Maven,Gradle,Git,Jenkins等,並且會將程式碼檢測結果推送回Sonar Qube並且在系統提供的UI介面上顯示出來

Sonar Qube的UI介面
image-20211129190039986

7.2 Sonar Qube環境搭建

7.2.1 Sonar Qube安裝

Sonar Qube在7.9版本中已經放棄了對MySQL的支援,並且建議在商業環境中採用PostgreSQL,那麼安裝Sonar Qube時需要依賴PostgreSQL。

並且這裡會安裝Sonar Qube的長期支援版本8.9

  • 拉取映象

    docker pull postgres
    docker pull sonarqube:8.9.3-community
    
  • 編寫docker-compoe.yml

    version: "3.1"
    services:
      db:
        image: postgres
        container_name: db
        ports:
          - 5432:5432
        networks:
          - sonarnet
        environment:
          POSTGRES_USER: sonar
          POSTGRES_PASSWORD: sonar
      sonarqube:
        image: sonarqube:8.9.3-community
        container_name: sonarqube
        depends_on:
          - db
        ports:
          - "9000:9000"
        networks:
          - sonarnet
        environment:
          SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
          SONAR_JDBC_USERNAME: sonar
          SONAR_JDBC_PASSWORD: sonar
    networks:
      sonarnet:
        driver: bridge
    
  • 啟動容器

    docker-compose up -d
    
  • 需要設定sysctl.conf檔案資訊

    設定vm.max_map_count
    image-20211207145215817
    image-20211207145342350

    並執行命令重新整理

    sysctl -p
    
  • 重新啟動需要一定時間啟動,可以可以檢視容器日誌,看到如下內容代表啟動成功

    容器日誌
    image-20211129191426344
  • 訪問Sonar Qube首頁

    登入
    image-20211129191537050
  • 還需要重新設定一次密碼

    重新設定密碼
    image-20211129193824428
  • Sonar Qube首頁

    Sonar Qube首頁
    image-20211129194148239
7.2.2 安裝中文外掛
安裝中文外掛
image-20211129194621820

安裝成功後需要重啟,安裝失敗重新點選install重灌即可。

安裝成功後,會檢視到重啟按鈕,點選即可

重啟按鈕
image-20211129194748765

重啟後檢視效果

首頁效果
image-20211129194931944

7.3 Sonar Qube基本使用

Sonar Qube的使用方式很多,Maven可以整合,也可以採用sonar-scanner的方式,再檢視Sonar Qube的檢測效果

7.3.1 Maven實現程式碼檢測
  • 修改Maven的settings.xml檔案配置Sonar Qube資訊

    <profile>
        <id>sonar</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <sonar.login>admin</sonar.login>
            <sonar.password>123456789</sonar.password>
            <sonar.host.url>http://192.168.11.11:9000</sonar.host.url>
        </properties>
    </profile>
    
  • 在程式碼位置執行命令:mvn sonar:sonar

    執行程式碼檢測
    image-20211129195430146
  • 檢視Sonar Qube介面檢測結果

    Sonar Qube檢測結果
    image-20211129195503762
7.3.2 Sonar-scanner實現程式碼檢測
  • 下載Sonar-scanner:https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/

    下載4.6.x版本即可,要求Linux版本

  • 解壓並配置sonar服務端資訊

    • 由於是zip壓縮包,需要安裝unzip解壓外掛

      yum -y install unzip
      
    • 解壓壓縮包

      unzip sonar-scanner-cli/sonar-scanner-cli-4.6.0.2311-linux.zip
      
    • 配置sonarQube服務端地址,修改conf下的sonar-scanner.properties

      配置服務端資訊
      image-20211130140043382
  • 執行命令檢測程式碼

    # 在專案所在目錄執行以下命令
    ~/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=demo -Dsonar.projectKey=java -Dsonar.java.binaries=target/
    

    Ps:主要檢視我的sonar-scanner執行命令的位置

    檢視日誌資訊
    image-20211130141303457
  • 檢視SonarQube介面檢測結果

    檢測結果
    image-20211130144608025

7.4 Jenkins整合Sonar Qube

Jenkins繼承Sonar Qube實現程式碼掃描需要先下載整合外掛

7.4.1 Jenkins安裝外掛
下載Sonar Qube外掛
image-20211129201625561
image-20211129201607240
image-20211129202147390
7.4.2 Jenkins配置Sonar Qube
  • 開啟Sonar Qube許可權驗證

    開啟Sonar Qube許可權校驗
    image-20211130144850186
  • 獲取Sonar Qube的令牌

    獲取令牌
    image-20211129203102334
  • 配置Jenkins的Sonar Qube資訊

    image-20211129203235019
    image-20211129203342171
    image-20211129203457604
7.4.3 配置Sonar-scanner
  • 將Sonar-scaner新增到Jenkins資料卷中並配置全域性配置

    配置Sonar-scanner
    image-20211130153628925
  • 配置任務的Sonar-scanner

    配置任務的Sonar-scanner
    image-20211130155849143
7.4.4 構建任務
構建任務
image-20211130160017465
image-20211130160047648

八、整合Harbor

8.1 Harbor介紹

前面在部署專案時,我們主要採用Jenkins推送jar包到指定伺服器,再透過指令碼命令讓目標伺服器對當前jar進行部署,這種方式在專案較多時,每個目標伺服器都需要將jar包製作成自定義映象再透過docker進行啟動,重複操作比較多,會降低專案部署時間。

我們可以透過Harbor作為私有的Docker映象倉庫。讓Jenkins統一將專案打包並製作成Docker映象釋出到Harbor倉庫中,只需要通知目標服務,讓目標服務統一去Harbor倉庫上拉取映象並在本地部署即可。

Docker官方提供了Registry映象倉庫,但是Registry的功能相對簡陋。Harbor是VMware公司提供的一款映象倉庫,提供了許可權控制、分散式釋出、強大的安全掃描與審查機制等功能

8.2 Harbor安裝

這裡採用原生的方式安裝Harbor。

  • 下載Harbor安裝包:https://github.com/goharbor/harbor/releases/download/v2.3.4/harbor-offline-installer-v2.3.4.tgz

  • 拖拽到Linux並解壓:

    tar -zxvf harbor-offline-installer-v2.3.4.tgz -C /usr/local/
    
  • 修改Harbor配置檔案:

    • 首先複製一份harbor.yml配置

      cp harbor.yml.tmpl harbor.yml
      
    • 編輯harbor.yml配置檔案

      配置Harbor檔案
      image-20211130215555218
  • 啟動Harbor

    ./install.sh
    
    檢視日誌
    image-20211130215941857
  • 登入Harbor

    登入Harbor
    image-20211130220028840
  • 首頁資訊

    首頁資訊
    image-20211130220111602

8.3 Harbor使用方式

Harbor作為映象倉庫,主要的互動方式就是將映象上傳到Harbor上,以及從Harbor上下載指定映象

在傳輸映象前,可以先使用Harbor提供的許可權管理,將專案設定為私有專案,並對不同使用者設定不同角色,從而更方便管理映象。

8.3.1 新增使用者構建專案
  • 建立使用者

    建立使用者
    image-20211201213427157
  • 構建專案(設定為私有)

    構建專案
    image-20211201213751780
  • 給專案追加使用者

    追加使用者管理
    image-20211201213832458
  • 切換測試使用者

    切換測試使用者
    image-20211201214008303
8.3.2 釋出映象到Harbor
  • 修改映象名稱

    名稱要求:harbor地址/專案名/映象名:版本

    修改映象名稱
    image-20211201221040200
  • 修改daemon.json,支援Docker倉庫,並重啟Docker

    修改daemon.json,支援Docker倉庫
    image-20211201215931237
  • 設定登入倉庫資訊

    docker login -u 使用者名稱 -p 密碼 Harbor地址
    
  • 推送映象到Harbor

    推送映象到Harbor
    image-20211201221225196
    image-20211201221300055
8.3.3 從Harbor拉取映象ls

跟傳統方式一樣,不過需要先配置/etc/docker/daemon.json檔案

{
        "registry-mirrors": ["https://pee6w651.mirror.aliyuncs.com"],
        "insecure-registries": ["192.168.11.11:80"]
}
拉取映象
image-20211201222450091
8.3.4 Jenkins容器使用宿主機Docker

構建映象和釋出映象到harbor都需要使用到docker命令。而在Jenkins容器內部安裝Docker官方推薦直接採用宿主機帶的Docker即可。

設定Jenkins容器使用宿主機Docker

  • 設定宿主機docker.sock許可權:

    sudo chown root:root /var/run/docker.sock
    sudo chmod o+rw /var/run/docker.sock
    
  • 新增資料卷

    version: "3.1"
    services:
      jenkins:
        image: jenkins/jenkins
        container_name: jenkins
        ports:
          - 8080:8080
          - 50000:50000
        volumes:
          - ./data/:/var/jenkins_home/
          - /usr/bin/docker:/usr/bin/docker
          - /var/run/docker.sock:/var/run/docker.sock
          - /etc/docker/daemon.json:/etc/docker/daemon.json
    
8.3.5 新增構建操作
製作自定義映象
image-20211229155834500
8.3.6 編寫部署指令碼

部署專案需要透過Publish Over SSH外掛,讓目標伺服器執行命令。為了方便一次性實現拉取映象和啟動的命令,推薦採用指令碼檔案的方式。

新增指令碼檔案到目標伺服器,再透過Publish Over SSH外掛讓目標伺服器執行指令碼即可。

  • 編寫指令碼檔案,新增到目標伺服器

    harbor_url=$1
    harbor_project_name=$2
    project_name=$3
    tag=$4
    port=$5
    
    imageName=$harbor_url/$harbor_project_name/$project_name:$tag
    
    containerId=`docker ps -a | grep ${project_name} | awk '{print $1}'`
    if [ "$containerId" != "" ] ; then
        docker stop $containerId
        docker rm $containerId
        echo "Delete Container Success"
    fi
    
    imageId=`docker images | grep ${project_name} | awk '{print $3}'`
    
    if [ "$imageId" != "" ] ; then
        docker rmi -f $imageId
        echo "Delete Image Success"
    fi
    
    docker login -u DevOps -p P@ssw0rd $harbor_url
    
    docker pull $imageName
    
    docker run -d -p $port:$port --name $project_name $imageName
    
    echo "Start Container Success"
    echo $project_name
    

    並設定許可權為可執行

    chmod a+x deploy.sh
    
    如圖
    image-20211203192047357
8.3.7 配置構建後操作
執行指令碼檔案
image-20211229155949038

九、Jenkins流水線

9.1 Jenkins流水線任務介紹

之前採用Jenkins的自由風格構建的專案,每個步驟流程都要透過不同的方式設定,並且構建過程中整體流程是不可見的,無法確認每個流程花費的時間,並且問題不方便定位問題。

Jenkins的Pipeline可以讓專案的釋出整體流程視覺化,明確執行的階段,可以快速的定位問題。並且整個專案的生命週期可以透過一個Jenkinsfile檔案管理,而且Jenkinsfile檔案是可以放在專案中維護。

所以Pipeline相對自由風格或者其他的專案風格更容易操作。

9.2 Jenkins流水線任務

9.2.1 構建Jenkins流水線任務
  • 構建任務

    構建Jenkins流水線任務
    image-20211202144429302
  • 生成Groovy指令碼

    Hello World指令碼生成
    image-20211202144531749
  • 構建後檢視檢視

    構建後檢視檢視
    image-20211202144616117
9.2.2 Groovy指令碼
  • Groovy指令碼基礎語法

    // 所有指令碼命令包含在pipeline{}中
    pipeline {  
      // 指定任務在哪個節點執行(Jenkins支援分散式)
        agent any
        
        // 配置全域性環境,指定變數名=變數值資訊
        environment{
          host = '192.168.11.11'
        }
    
        // 存放所有任務的合集
        stages {
          // 單個任務
            stage('任務1') {
              // 實現任務的具體流程
                steps {
                    echo 'do something'
                }
            }
        // 單個任務
            stage('任務2') {
              // 實現任務的具體流程
                steps {
                    echo 'do something'
                }
            }
            // ……
        }
    }
    
  • 編寫例子測試

    pipeline {
        agent any
    
        // 存放所有任務的合集
        stages {
            stage('拉取Git程式碼') {
                steps {
                    echo '拉取Git程式碼'
                }
            }
    
            stage('檢測程式碼質量') {
                steps {
                    echo '檢測程式碼質量'
                }
            }
    
            stage('構建程式碼') {
                steps {
                    echo '構建程式碼'
                }
            }
    
            stage('製作自定義映象併發布Harbor') {
                steps {
                    echo '製作自定義映象併發布Harbor'
                }
            }
    
            stage('基於Harbor部署工程') {
                steps {
                    echo '基於Harbor部署工程'
                }
            }
        }
    }
    
    配置Grovvy指令碼
    image-20211202145155428
  • 檢視效果

    檢視效果
    image-20211202145240166

Ps:涉及到特定指令碼,Jenkins給予了充足的提示,可以自動生成命令

生成命令位置
image-20211202145349043
9.2.3 Jenkinsfile實現

Jenkinsfile方式需要將指令碼內容編寫到專案中的Jenkinsfile檔案中,每次構建會自動拉取專案並且獲取專案中Jenkinsfile檔案對專案進行構建

  • 配置pipeline

    配置pipeline
    image-20211202151127254
  • 準備Jenkinsfile

    準備Jenkinsfile檔案
    image-20211202151155145
  • 測試效果

    測試效果
    image-20211202151225161

9.3 Jenkins流水線任務實現

9.3.1 引數化構建

新增引數化構建,方便選擇不的專案版本

Git引數化構建
image-20211202191944277
9.3.2 拉取Git程式碼

透過流水線語法生成Checkout程式碼的指令碼

語法生成
image-20211202192047619

image-20211202192129895將*/master更改為標籤${tag}

pipeline {
    agent any
    stages {

        stage('拉取Git程式碼') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
            }
        }
    }
}
9.3.3 構建程式碼

透過指令碼執行mvn的構建命令

pipeline {
    agent any

    stages {

        stage('拉取Git程式碼') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
            }
        }

        stage('構建程式碼') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
}

9.3.4 程式碼質量檢測

透過指令碼執行sonar-scanner命令即可

pipeline {
    agent any

    stages {

        stage('拉取Git程式碼') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
            }
        }

        stage('構建程式碼') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }

        stage('檢測程式碼質量') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa' 
            }
        }
    }
}

9.3.5 製作自定義映象併發布
  • 生成自定義映象指令碼

    pipeline {
        agent any
        environment{
            harborHost = '192.168.11.11:80'
            harborRepo = 'repository'
            harborUser = 'DevOps'
            harborPasswd = 'P@ssw0rd'
        }
    
        // 存放所有任務的合集
        stages {
    
            stage('拉取Git程式碼') {
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
                }
            }
    
            stage('構建程式碼') {
                steps {
                    sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
                }
            }
    
            stage('檢測程式碼質量') {
                steps {
                    sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa' 
                }
            }
    
            stage('製作自定義映象併發布Harbor') {
                steps {
                    sh '''cp ./target/*.jar ./docker/
                    cd ./docker
                    docker build -t ${JOB_NAME}:${tag} ./'''
    
                    sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
                    docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
                    docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
                }
            }
        }
    }
    
  • 生成Publish Over SSH指令碼

    pipeline {
        agent any
        environment{
            harborHost = '192.168.11.11:80'
            harborRepo = 'repository'
            harborUser = 'DevOps'
            harborPasswd = 'P@ssw0rd'
        }
    
        // 存放所有任務的合集
        stages {
    
            stage('拉取Git程式碼') {
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
                }
            }
    
            stage('構建程式碼') {
                steps {
                    sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
                }
            }docker
    
            stage('檢測程式碼質量') {
                steps {
                    sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098' 
                }
            }
    
            stage('製作自定義映象併發布Harbor') {
                steps {
                    sh '''cp ./target/*.jar ./docker/
                    cd ./docker
                    docker build -t ${JOB_NAME}:${tag} ./'''
    
                    sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
                    docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
                    docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
                }
            }
            
            stage('目標伺服器拉取映象並執行') {
                steps {
                    sshPublisher(publishers: [sshPublisherDesc(configName: 'testEnvironment', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/usr/bin/deploy.sh $harborHost $harborRepo $JOB_NAME $tag $port ", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }
            }
        }
    }
    

Ps:由於採用變數,記得使用雙引號

9.4 Jenkins流水線整合釘釘

在程式部署成功後,可以透過釘釘的機器人及時向群眾傳送部署的最終結果通知

  • 安裝外掛

    安裝外掛
    image-20211209151549412
  • 釘釘內部建立群組並構建機器人

    釘釘內部建立群組並構建機器人
    image-20211209152217433
    image-20211209152252050
    image-20211209152403312

    最終或獲取到Webhook資訊

    https://oapi.dingtalk.com/robot/send?access_token=kej4ehkj34gjhg34jh5bh5jb34hj53b4
    
  • 系統配置新增釘釘通知

    配置釘釘通知
    image-20211209162923440
  • 任務中追加流水線配置

    pipeline {
        agent any
    
        environment {
            sonarLogin = '2bab7bf7d5af25e2c2ca2f178af2c3c55c64d5d8'
            harborUser = 'admin'
            harborPassword = 'Harbor12345'
            harborHost = '192.168.11.12:8888'
            harborRepo = 'repository'
        }
    
        stages {
            stage('拉取Git程式碼'){
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '$tag']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/lsx.git']]])
                }
            }
            stage('Maven構建程式碼'){
                steps {
                    sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
                }
            }
            stage('SonarQube檢測程式碼'){
                steps {
                    sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=${sonarLogin}'
                }
            }
            stage('製作自定義映象'){
                steps {
                    sh '''cd docker
                    mv ../target/*.jar ./
                    docker build -t ${JOB_NAME}:$tag .
                    '''
                }
            }
    
            stage('推送自定義映象'){
                steps {
                    sh '''docker login -u ${harborUser} -p ${harborPassword} ${harborHost}
                    docker tag ${JOB_NAME}:$tag ${harborHost}/${harborRepo}/${JOB_NAME}:$tag
                    docker push ${harborHost}/${harborRepo}/${JOB_NAME}:$tag'''
                }
            }
    
            stage('通知目標伺服器'){
                steps {
                    sshPublisher(publishers: [sshPublisherDesc(configName: 'centos-docker', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/usr/bin/deploy.sh $harborHost $harborRepo $JOB_NAME $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }  
            }
        }
        post {
            success {
                dingtalk (
                    robot: 'Jenkins-DingDing',
                    type:'MARKDOWN',
                    title: "success: ${JOB_NAME}",
                    text: ["- 成功構建:${JOB_NAME}專案!\n- 版本:${tag}\n- 持續時間:${currentBuild.durationString}\n- 任務:#${JOB_NAME}"]
                )
            }
            failure {
                dingtalk (
                    robot: 'Jenkins-DingDing',
                    type:'MARKDOWN',
                    title: "fail: ${JOB_NAME}",
                    text: ["- 失敗構建:${JOB_NAME}專案!\n- 版本:${tag}\n- 持續時間:${currentBuild.durationString}\n- 任務:#${JOB_NAME}"]
                )
            }
        }
    }
    
  • 檢視效果

    釘釘通知效果
    image-20211209163021396

十、Kubernetes編排工具

10.1 Kubernetes介紹

Kubernetes是一個開源的,用於管理雲平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單並且高效(powerful),Kubernetes提供了應用部署,規劃,更新,維護的一種機制。

Kubernetes一個核心的特點就是能夠自主的管理容器來保證雲平臺中的容器按照使用者的期望狀態執行著,管理員可以載入一個微型服務,讓規劃器來找到合適的位置,同時,Kubernetes也系統提升工具以及人性化方面,讓使用者能夠方便的部署自己的應用。

Kubernetes主要能幫助我們完成:

  • 服務發現和負載均衡

    Kubernetes 可以使用 DNS 名稱或自己的 IP 地址公開容器,如果進入容器的流量很大, Kubernetes 可以負載均衡並分配網路流量,從而使部署穩定。

  • 儲存編排

    Kubernetes 允許你自動掛載你選擇的儲存系統,比如本地儲存,類似Docker的資料卷。

  • 自動部署和回滾

    你可以使用 Kubernetes 描述已部署容器的所需狀態,它可以以受控的速率將實際狀態 更改為期望狀態。Kubernetes 會自動幫你根據情況部署建立新容器,並刪除現有容器給新容器提供資源。

  • 自動完成裝箱計算

    Kubernetes 允許你設定每個容器的資源,比如CPU和記憶體。

  • 自我修復

    Kubernetes 重新啟動失敗的容器、替換容器、殺死不響應使用者定義的容器,並執行狀況檢查的容器。

  • 秘鑰與配置管理

    Kubernetes 允許你儲存和管理敏感資訊,例如密碼、OAuth 令牌和 ssh 金鑰。你可以在不重建容器映象的情況下部署和更新金鑰和應用程式配置,也無需在堆疊配置中暴露金鑰。

10.2 Kubernetes架構

Kubernetes 搭建需要至少兩個節點,一個Master負責管理,一個Slave搭建在工作伺服器上負責分配。

kubernetes架構
image-20211210114507638

從圖中可以看到各個元件的基本功能:

  • API Server:作為K8s通訊的核心元件,K8s內部互動以及接收傳送指令的元件。
  • controller-manager:作為K8s的核心元件,主要做資源排程,根據叢集情況分配資源
  • etcd:一個key-value的資料庫,儲存儲存叢集的狀態資訊
  • scheduler:負責排程每個工作節點
  • cloud-controller-manager:負責排程其他雲服務產品
  • kubelet:管理Pods上面的容器。
  • kube-proxy:負責處理其他Slave或客戶端的請求。
  • Pod:可以理解為就是執行的容器

10.3 Kubernetes安裝

這裡會採用https://kuboard.cn/提供的方式安裝K8s,安裝單Master節點

  • 要求使用Centos7.8版本:https://vault.centos.org/7.8.2003/isos/x86_64/CentOS-7-x86_64-Minimal-2003.iso
  • 至少2臺 2核4G 的伺服器

安裝流程

安裝流程
image-20211210190653687

準備好伺服器後開始安裝

  • 重新設定hostname,不允許為localhost

    # 修改 hostname,名字不允許使用下劃線、小數點、大寫字母,不能叫master
    hostnamectl set-hostname your-new-host-name
    # 檢視修改結果
    hostnamectl status
    # 設定 hostname 解析
    echo "127.0.0.1   $(hostname)" >> /etc/hosts
    
  • 要求2臺服務之間可以相互通訊

  • 安裝軟體

    # 阿里雲 docker hub 映象
    export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
    curl -sSL https://kuboard.cn/install-script/v1.19.x/install_kubelet.sh | sh -s 1.19.5
    

首先初始化Master節點

關於初始化時用到的環境變數

  • APISERVER_NAME 不能是 master 的 hostname
  • APISERVER_NAME 必須全為小寫字母、數字、小數點,不能包含減號
  • POD_SUBNET 所使用的網段不能與 master節點/worker節點 所在的網段重疊。該欄位的取值為一個 CIDR 值,如果您對 CIDR 這個概念還不熟悉,請仍然執行 export POD_SUBNET=10.100.0.0/16 命令,不做修改
  • 設定ip,域名,網段並執行初始化操作

    # 只在 master 節點執行
    # 替換 x.x.x.x 為 master 節點實際 IP(請使用內網 IP)
    # export 命令只在當前 shell 會話中有效,開啟新的 shell 視窗後,如果要繼續安裝過程,請重新執行此處的 export 命令
    export MASTER_IP=192.168.11.32
    # 替換 apiserver.demo 為 您想要的 dnsName
    export APISERVER_NAME=apiserver.demo
    # Kubernetes 容器組所在的網段,該網段安裝完成後,由 kubernetes 建立,事先並不存在於您的物理網路中
    export POD_SUBNET=10.100.0.1/16
    echo "${MASTER_IP}    ${APISERVER_NAME}" >> /etc/hosts
    curl -sSL https://kuboard.cn/install-script/v1.19.x/init_master.sh | sh -s 1.19.5
    
  • 檢查Master啟動狀態

    # 只在 master 節點執行
    
    # 執行如下命令,等待 3-10 分鐘,直到所有的容器組處於 Running 狀態
    watch kubectl get pod -n kube-system -o wide
    
    # 檢視 master 節點初始化結果
    kubectl get nodes -o wide
    
Ps:如果出現NotReady的情況執行(最新版本的BUG,1.19一般沒有)
docker pull quay.io/coreos/flannel:v0.10.0-amd64 
mkdir -p /etc/cni/net.d/
cat <<EOF> /etc/cni/net.d/10-flannel.conf
{"name":"cbr0","type":"flannel","delegate": {"isDefaultGateway": true}}
EOF
mkdir /usr/share/oci-umount/oci-umount.d -p
mkdir /run/flannel/
cat <<EOF> /run/flannel/subnet.env
FLANNEL_NETWORK=172.100.0.0/16
FLANNEL_SUBNET=172.100.1.0/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
EOF
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml

安裝網路服務外掛

export POD_SUBNET=10.100.0.0/16
kubectl apply -f https://kuboard.cn/install-script/v1.22.x/calico-operator.yaml
wget https://kuboard.cn/install-script/v1.22.x/calico-custom-resources.yaml
sed -i "s#192.168.0.0/16#${POD_SUBNET}#" calico-custom-resources.yaml
kubectl apply -f calico-custom-resources.yaml

初始化worker節點

  • 獲取Join命令引數,在Master節點執行

    # 只在 master 節點執行
    kubeadm token create --print-join-command
    
    獲取命令
    image-20211213183025291
  • 在worker節點初始化

    # 只在 worker 節點執行
    # 替換 x.x.x.x 為 master 節點的內網 IP
    export MASTER_IP=192.168.11.32
    # 替換 apiserver.demo 為初始化 master 節點時所使用的 APISERVER_NAME
    export APISERVER_NAME=apiserver.demo
    echo "${MASTER_IP}    ${APISERVER_NAME}" >> /etc/hosts
    
    # 替換為 master 節點上 kubeadm token create 命令的輸出
    kubeadm join apiserver.demo:6443 --token vwfilu.3nhndohc5gn1jv9k     --discovery-token-ca-cert-hash sha256:22ff15cabfe87ab48a7db39b3bbf986fee92ec92eb8efc7fe9b0abe2175ff0c2
    

檢查最終執行效果

  • 在 master 節點上執行

    # 只在 master 節點執行
    kubectl get nodes -o wide
    
Ps:如果出現NotReady的情況執行(最新版本的BUG,1.19一般沒有)
docker pull quay.io/coreos/flannel:v0.10.0-amd64 
mkdir -p /etc/cni/net.d/
cat <<EOF> /etc/cni/net.d/10-flannel.conf
{"name":"cbr0","type":"flannel","delegate": {"isDefaultGateway": true}}
EOF
mkdir /usr/share/oci-umount/oci-umount.d -p
mkdir /run/flannel/
cat <<EOF> /run/flannel/subnet.env
FLANNEL_NETWORK=172.100.0.0/16
FLANNEL_SUBNET=172.100.1.0/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
EOF
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml
  • 輸出結果如下所示:

    [root@k8smaster ~]# kubectl get nodes
    
    搭建成功效果
    image-20211210184851810

安裝Kuboard管理K8s叢集

  • 安裝Kuboard

    kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3.yaml
    # 您也可以使用下面的指令,唯一的區別是,該指令使用華為雲的映象倉庫替代 docker hub 分發 Kuboard 所需要的映象
    # kubectl apply -f https://addons.kuboard.cn/kuboard/kuboard-v3-swr.yaml
    
  • 檢視啟動情況

    watch kubectl get pods -n kuboard
    
    檢視效果
    image-20211213184701784
  • 在瀏覽器中開啟連結 http://your-node-ip-address:30080

    首頁
    image-20211213184742709
  • 輸入初始使用者名稱和密碼,並登入

    • 使用者名稱: admin
    • 密碼: Kuboard123
    首頁效果
    image-20211213184840120

10.4 Kubernetes操作

首先我們要了解Kubernetes在執行我們的資源時,關聯到了哪些內容

  • 資源的構建方式:

    • 採用kubectl的命令方式
    • yaml檔案方式
10.4.1 Namespace
  • 名稱空間:主要是為了對Kubernetes中執行的資源進行過隔離, 但是網路是互通的,類似Docker的容器,可以將多個資源配置到一個NameSpace中。而NameSpace可以對不同環境進行資源隔離,預設情況下Kubernetes提供了default名稱空間,在構建資源時,如果不指定資源,預設採用default資源。
    命令方式:

    # 檢視現有的全部名稱空間
    kubectl get ns
    
    # 構建名稱空間
    kubectl create ns 名稱空間名稱
    
    # 刪除現有名稱空間, 並且會刪除空間下的全部資源
    kubectl delete ns 名稱空間名稱
    

    yaml檔案方式:(構建資源時,設定名稱空間)

    apiVersion: v1
    kind: Namespace
    metadata:
      name: test
    
10.4.2 Pod
  • Pod:Kubernetes執行的一組容器,Pod是Kubernetes的最小單位,但是對於Docker而然,Pod中會執行多個Docker容器

    • 命令方式:

      # 檢視所有執行的pod
      kubectl get pods -A
      
      # 檢視指定Namespace下的Pod
      kubectl get pod [-n 名稱空間]  #(預設default)
      
      # 建立Pod
      kubectl run pod名稱 --image=映象名稱
      
      # 檢視Pod詳細資訊
      kubectl describe pod pod名稱
      
      # 刪除pod
      kubectl delete pod pod名稱 [-n 名稱空間]  #(預設default)
      
      # 檢視pod輸出的日誌
      kubectl logs -f pod名稱
      
      # 進去pod容器內部
      kubectl exec -it pod名稱 -- bash
      
      # 檢視kubernetes給Pod分配的ip資訊,並且透過ip和容器的埠,可以直接訪問
      kubectl get pod -owide
      
    • yaml方式(推薦)

      apiVersion: v1
      kind: Pod
      metadata:
        labels:
          run: 執行的pod名稱
        name: pod名稱
        namespace: 名稱空間
      spec:
        containers:
        - image: 映象名稱
          name: 容器名稱
      
      # 啟動Pod:kubectl apply -f yaml檔名稱
      # 刪除Pod:kubectl delete -f yaml檔名稱
      
    • Pod中執行多個容器

      apiVersion: v1
      kind: Pod
      metadata:
        labels:
          run: 執行的pod名稱
        name: pod名稱
        namespace: 名稱空間
      spec:
        containers:
        - image: 映象名稱
          name: 容器名稱
        - image: 映象名稱
          name: 容器名稱
      …………    
      

      啟動後可以檢視到

      Kuboard效果
      image-20220104203155749
10.4.3 Deployment

部署時,可以透過Deployment管理和編排Pod

Deployment部署實現

  • 命令方式

    # 基於Deployment啟動容器
    kubectl create deployment deployment名稱 --image=映象名稱
    # 用deployment啟動的容器會在被刪除後自動再次建立,達到故障漂移的效果
    # 需要使用deploy的方式刪除deploy
    # 檢視現在的deployment
    kubectl get deployment
    
    # 刪除deployment
    kubectl delete deployment deployment名稱
    
    # 基於Deployment啟動容器並設定Pod叢集數
    kubectl create deployment deployment名稱 --image=映象名稱 --replicas 叢集個數
    
  • 配置檔案方式

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
           image: nginx
           ports:
           - containerPort: 80
    

    正常使用kubectl執行yaml即可

彈性伸縮功能

# 基於scale實現彈性伸縮
kubectl scale deploy/Deployment名稱 --replicas 叢集個數
# 或者修改yaml檔案
kubectl edit deploy Deployment名稱
圖形化頁面修改
image-20220104210823057

灰度釋出

Deploy可以在部署新版本資料時,成功啟動一個pod,才會下線一個老版本的Pod

kubectl set image deployment/Deployment名稱 容器名=映象:版本
10.4.4 Service

可以將多個Pod對外暴露一個Service,讓客戶端可以透過Service訪問到這一組Pod,並且可以實現負載均衡

ClusterIP方式:

ClusterIP是叢集內部Pod之間的訪問方式

  • 命令實現效果

    # 透過生成service對映一個Deployment下的所有pod中的某一個埠的容器
    kubectl expose deployment Deployment名稱 --port=Service埠號 --target-port=Pod內容器埠
    

    之後透過kubectl get service檢視Service提供的ip,即可訪問

    kubectl get service
    image-20220104214659229

    也可以透過Deployment名稱.namespace名稱.svc作為域名訪問

    在服務容器內執行
    image-20220104215030265

NodePort方式

ClusterIP的方式只能在Pod內部實現訪問,但是一般需要對外暴露閘道器,所以需要NodePort的方式Pod外暴露訪問

  • 命令實現方式

    # 透過生成service對映一個Deployment下的所有pod中的某一個埠的容器
    kubectl expose deployment Deployment名稱 --port=Service埠號 --target-port=Pod內容器埠 --type=NodePort
    
    檢視Service效果
    image-20220104222750733
    image-20220104222819455

Service也可以透過yaml檔案實現

apiVersion: v1
kind: Service
metadata:
  labels
    app: nginx
  name: nginx
  spec:
    selector:
      app: nginx
    ports:
    - port: 8888
     protocol: TCP
     targetPort: 80

透過apply啟動就也可以建立Service

測試效果-Deployment部署,透過Service暴露

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deployment
  template:
    metadata:
      labels:
        app: nginx-deployment
    spec:
      containers:
      - name: nginx-deployment
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-service
  name: nginx-service
spec:
  selector:
    app: nginx-deployment
  ports:
  - port: 8888
    protocol: TCP
    targetPort: 80
  type: NodePort

可以檢視到暴露的資訊

Service資訊
image-20220105205334996
10.4.5 Ingress

Kubernetes推薦將Ingress作為所有Service的入口,提供統一的入口,避免多個服務之間需要記錄大量的IP或者域名,畢竟IP可能改變,服務太多域名記錄不方便。

Ingress底層其實就是一個Nginx, 可以在Kuboard上直接點選安裝

Kuboard安裝
image-20220105153343642
image-20220105153416367

因為副本數預設為1,但是k8s整體叢集就2個節點,所以顯示下面即為安裝成功

安裝成功
image-20220105153502619

可以將Ingress接收到的請求轉發到不同的Service中。

推薦使用yaml檔案方式

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  ingressClassName: ingress
  rules:
  - host: nginx.mashibing.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 8888
啟動時問題
image-20220105203819715

Kuboard安裝的Ingress有admission的校驗配置,需要先刪除配置再啟動

找到指定的ingress的校驗資訊,刪除即可

刪除資訊
image-20220105204434044
# 檢視校驗webhook的配置
kubectl get -A ValidatingWebhookConfiguration

# 刪除指定的校驗
kubectl delete ValidatingWebhookConfiguration ingress-nginx-admission-my-ingress-controller

配置本地hosts檔案

配置hosts
image-20220105204921272

記下來既可以訪問在Service中暴露的Nginx資訊

服透過Ingress訪問
image-20220105205407393

10.5 Jenkins整合Kubernetes

10.5.1 準備部署的yml檔案
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: test
  name: pipeline
  labels:
    app: pipeline
spec:
  replicas: 2
  selector:
    matchLabels:
      app: pipeline
  template:
    metadata:
      labels:
        app: pipeline    
    spec:
      containers:
      - name: pipeline
        image: 192.168.11.102:80/repo/pipeline:v4.0.0
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  namespace: test
  labels:
    app: pipeline
  name: pipeline  
spec:
  selector:
    app: pipeline
  ports:
  - port: 8081
    targetPort: 8080
  type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: test
  name: pipeline
spec:
  ingressClassName: ingress
  rules:
  - host: mashibing.pipeline.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: pipeline
            port:
              number: 8081
10.5.2 Harbor私服配置

在嘗試用kubernetes的yml檔案啟動pipeline服務時,會出現Kubernetes無法拉取映象的問題,這裡需要在kubernetes所在的Linux中配置Harbor服務資訊,並且保證Kubernetes可以拉取Harbor上的映象

  • 設定Master和Worker的私服地址資訊

    設定Harbor私服地址
    1642498962716
  • 在Kuboard上設定私服密文資訊

    設定密文並測試
    1642498994935

    按照複製指令的位置測試認證,效果如下

    測試效果
    1642499172789
10.5.3 測試使用效果

執行kubectl命令,基於yml啟動服務,並且基於部署後服務的提示資訊以及Ingress的設定,直接訪問

1642499368121
1642499788199
10.5.3 Jenkins遠端呼叫
  • 將pipeline.yml配置到Gitlab中

    配置yml檔案
    1642499885324
  • 配置Jenkins的目標伺服器,可以將yml檔案傳輸到K8s的Master上

    設定目標伺服器
    1642499992148
  • 修改Jenkinsfile,重新設定流水線任務指令碼,並測試效果

    傳遞yml檔案指令碼
    1642500061153
    1642500102996
  • 設定Jenkins無密碼登入k8s-master

    將Jenkins中公鑰資訊複製到k8s-master的~/.ssh/authorized_keysz中,保證遠端連線無密碼

    遠端執行命令無需密碼
    1642500239406
  • 設定執行kubectl的指令碼到Jenkinsfile

    設定Jenkinsfile
    1642500378788
  • 執行檢視效果

    執行流水線
    1642500413802

    可以檢視到yml檔案是由變化的, 這樣k8s就會重新載入

  • 檢視效果

    效果
    1642500474036

Ps:這種方式更適應與CD操作,將專案將基於某個版本部署到指定的目標伺服器

10.6 基於GitLab的WebHooks

這裡要實現自動化的一個CI操作,也就是開發人員Push程式碼到Git倉庫後,Jenkins會自動的構建專案,將最新的提交點程式碼構建並進行打包部署,這裡區別去上述的CD操作,CD操作需要基於某個版本進行部署,而這裡每次都是將最新的提交點整合到主幹上並測試。

10.6.1 WebHooks通知

開啟Jenkins的自動構建

構建觸發器
1642500817131

設定Gitlab的Webhooks

設定Gitlab的Webhooks
1642500933316

需要關閉Jenkins的Gitlab認證

關閉Jenkins的Gitlab認證
1642501016474

再次測試Gitlab

再次測試
1642501065243
10.6.2 修改配置

修改Jenkinsfile實現基於最新提交點實現持續整合效果,將之前引用${tag}的全部去掉

// 所有的指令碼命令都放在pipeline中
pipeline{
  // 指定任務再哪個叢集節點中執行
  agent any

  // 宣告全域性變數,方便後面使用
  environment {
    harborUser = 'admin'
        harborPasswd = 'Harbor12345'
        harborAddress = '192.168.11.102:80'
        harborRepo = 'repo'
  }

    stages {
        stage('拉取git倉庫程式碼') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.11.101:8929/root/mytest.git']]])
            }
        }
        stage('透過maven構建專案') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }
        stage('透過SonarQube做程式碼質量檢測') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.source=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=40306ae8ea69a4792df2ceb4d9d25fe8a6ab1701'
            }
        }
        stage('透過Docker製作自定義映象') {
            steps {
                sh '''mv ./target/*.jar ./docker/
                docker build -t ${JOB_NAME}:latest ./docker/'''
            }
        }
        stage('將自定義映象推送到Harbor') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborAddress}
                docker tag ${JOB_NAME}:latest  ${harborAddress}/${harborRepo}/${JOB_NAME}:latest
                docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:latest '''
            }
        }
        stage('將yml檔案傳到k8s-master上') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'k8s', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'pipeline.yml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
        stage('遠端執行k8s-master的kubectl命令') {
            steps {
               sh '''ssh root@192.168.11.201 kubectl apply -f /usr/local/k8s/pipeline.yml
                ssh root@192.168.11.201 kubectl rollout restart deployment pipeline -n test'''
            }
        }

    }
    post {
        success {
            dingtalk(
                robot: 'Jenkins-DingDing',
                type: 'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功構建:${JOB_NAME}! \n- 版本:latest \n- 持續時間:${currentBuild.durationString}" ]
            )
        }
        failure {
            dingtalk(
                robot: 'Jenkins-DingDing',
                type: 'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 構建失敗:${JOB_NAME}! \n- 版本:latest \n- 持續時間:${currentBuild.durationString}" ]
            )
        }
    }
}

修改pipeline.yml,更改映象版本

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: test
  name: pipeline
  labels:
    app: pipeline
spec:
  replicas: 2
  selector:
    matchLabels:
      app: pipeline
  template:
    metadata:
      labels:
        app: pipeline    
    spec:
      containers:
      - name: pipeline
        image: 192.168.11.102:80/repo/pipeline:latest   # 這裡
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
# 省略其他內容…………
10.6.3 滾動更新

因為pipeline沒有改變時,每次不會重新載入,這樣會導致Pod中的容器不會動態更新,這裡需要使用kubectl的rollout restart命令滾動更新

設定Jenkinsfle
1642501521065
1642501549176

相關文章