微服務從程式碼到k8s部署應有盡有大結局(k8s部署)

語言: CN / TW / HK

我們用一個系列來講解從需求到上線、從程式碼到k8s部署、從日誌到監控等各個方面的微服務完整實踐。

整個專案使用了go-zero開發的微服務,基本包含了go-zero以及相關go-zero作者開發的一些中介軟體,所用到的技術棧基本是go-zero專案組的自研元件,基本是go-zero全家桶了。

實戰專案地址:https://github.com/Mikaelemmmm/go-zero-looklook

1、概述

上一節,我們已經把gitlab、jenkins、harbor、k8s都已經搭建好了,這一節我們來編寫jenkins的pipline將我們的服務通過jenkins完整的釋出到k8s中。

2、部署中介軟體

將mysql、redis、es等部署到k8s之外 , 模擬用作線上獨立環境(至於線上你想把某些中介軟體部署到k8s內部這個自行處理,本次重點是如何將go-zero開發的微服務部署到k8s叢集內部),這裡我就直接使用專案下的docker-compose-env.yaml了,把所有依賴的第三方中介軟體環境直接安裝在srv-data.com(192.168.1.181)這臺伺服器,前提是這臺伺服器已經安裝好docker、docker-compose。

登陸到 192.168.1.181

$ mkdir data && cd data && vim docker-compose.yml
$ docker-compose up -d
$ docker-compose ps #檢視確認

3、獨立配置

將每個服務的配置都獨立出來,統一放在一個git倉庫,這樣只給一個人線上倉庫的許可權,如果線上配置有變直接修改這個倉庫的檔案,在jenkins做cd的時候,會先拉取程式碼再拉取對應服務的配置自動構建,具體可以看後面的pipline。

【問】為什麼不用配置中心?

1)修改db、redis等需要重啟服務,但是有一些配置又不需要重啟服務,運維又要去記,記混了比較容易造成線上事故

2)方便回滾。我們發新版本到線上,並且又改了新版本配置。這時候線上使用者反饋有問題,線上需要快速回滾的話,如果我們使用將檔案構建到映象中,直接使用k8s一行命令就可以將上一個版本程式碼加配置直接回滾回來。如果使用了配置中心,回滾了程式碼,還要將上個版本的配置去配置中心改回來,很麻煩。

獨立線上倉庫目錄結構如下(這個結構是跟pipline中寫法相關的)

倉庫地址 : https://github.com/Mikaelemmmm/go-zero-looklook-pro-conf , 直接下載就好

1、修改配置中的中介軟體,資料庫、redis等都要改成192.168.1.181這臺機器,我們把這臺機器當成線上環境的中介軟體。

2、另外一個就是我們的服務發現,線上我們部署在k8s中,go-zero直接支援k8s服務發現,所以不需要etcd等,我們在配置zrpc client的時候,要改成target,k8s的配置方式。

4、編寫 jenkins 的 pipline

4.1 配置引數

訪問 http://192.168.1.180:8989/ 開啟jenkins,進入jenkins首頁,點選左側選單新建Item

我們先建立 identity 授權服務的流水線

然後點選“General” , 選擇“This project is parameterized” , "新增引數",“Choice Parameter”,如下圖

然後編寫內容如下

直接儲存。

4.2 編寫pipline

向下滑動找到Pipeline script,填寫指令碼內容

pipeline {
  agent any
  parameters {
      gitParameter name: 'branch', 
      type: 'PT_BRANCH',
      branchFilter: 'origin/(.*)',
      defaultValue: 'master',
      selectedValue: 'DEFAULT',
      sortMode: 'ASCENDING_SMART',
      description: '選擇需要構建的分支'
  }

  stages {
      stage('服務資訊')    {
          steps {
              sh 'echo 分支:$branch'
              sh 'echo 構建服務型別:${JOB_NAME}-$type'
          }
      }

      stage('拉取程式碼') {
          steps {
              checkout([$class: 'GitSCM', 
              branches: [[name: '$branch']],
              doGenerateSubmoduleConfigurations: false, 
              extensions: [], 
              submoduleCfg: [],
              userRemoteConfigs: [[credentialsId: 'gitlab-cert', url: 'ssh://[email protected]:2222/root/go-zero-looklook.git']]])
          }   
      }

      stage('獲取commit_id') {
          steps {
              echo '獲取commit_id'
              git credentialsId: 'gitlab-cert', url: 'ssh://[email protected]:2222/root/go-zero-looklook.git'
              script {
                  env.commit_id = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
              }
          }
      }

      stage('拉取配置檔案') {
              steps {
                  checkout([$class: 'GitSCM', 
                  branches: [[name: '$branch']],
                  doGenerateSubmoduleConfigurations: false, 
                  extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'conf']], 
                  submoduleCfg: [],
                  userRemoteConfigs: [[credentialsId: 'gitlab-cert', url: 'ssh://[email protected]:2222/root/go-zero-looklook-pro-conf.git']]])
              }   
      }

      stage('goctl版本檢測') {
          steps{
              sh '/usr/local/bin/goctl -v'
          }
      }

      stage('Dockerfile Build') {
          steps{
                 sh 'yes | cp  -rf conf/${JOB_NAME}/${type}/${JOB_NAME}.yaml  app/${JOB_NAME}/cmd/${type}/etc'   //線上配置檔案
                 sh 'cd app/${JOB_NAME}/cmd/${type} && /usr/local/bin/goctl docker -go ${JOB_NAME}.go && ls -l'
                 script{
                     env.image = sh(returnStdout: true, script: 'echo ${JOB_NAME}-${type}:${commit_id}').trim()
                 }
                 sh 'echo 映象名稱:${image} && cp app/${JOB_NAME}/cmd/${type}/Dockerfile ./  && ls -l && docker build  -t ${image} .'
          }
      }

      stage('上傳到映象倉庫') {
          steps{
          	  //docker login 這裡要注意,會把賬號密碼輸出到jenkins頁面,可以通過port.sh類似方式處理,官網文件有這裡我就不詳細寫了
              sh 'docker login --username=${docker_username} --password=${docker_pwd} http://${docker_repo}' 
              sh 'docker tag  ${image} ${docker_repo}/go-zero-looklook/${image}'
              sh 'docker push ${docker_repo}/go-zero-looklook/${image}'
          }
      }

      stage('部署到k8s') {
          steps{
              script{
                  env.deployYaml = sh(returnStdout: true, script: 'echo ${JOB_NAME}-${type}-deploy.yaml').trim()
                  env.port=sh(returnStdout: true, script: '/root/port.sh ${JOB_NAME}-${type}').trim()
              }

              sh 'echo ${port}'

              sh 'rm -f ${deployYaml}'
              sh '/usr/local/bin/goctl kube deploy -secret docker-login -replicas 2 -nodePort 3${port} -requestCpu 200 -requestMem 50 -limitCpu 300 -limitMem 100 -name ${JOB_NAME}-${type} -namespace go-zero-looklook -image ${docker_repo}/${image} -o ${deployYaml} -port ${port} --home /root/template'
              sh '/usr/local/bin/kubectl apply -f ${deployYaml}'
          }
      }

       stage('Clean') {
           steps{
               sh 'docker rmi -f ${image}'
               sh 'docker rmi -f ${docker_repo}/${image}'
               cleanWs notFailBuild: true
           }
       }
  }
}

非常重要!!!

  1. 構建優化:pipline中生成dockerfile的時候,我們是使用k8s方式部署不需要etcd,但是這種方式部署需要指定賬號(有去k8s的endpoints中get的許可權,使用預設default就好了,每次建立一個新的名稱空間k8s會自動幫我們建立好一個default),但是使用goctl 生成的 k8s yml沒有新增指定賬號選項,這個已經反饋了,可能後續版本會加上,這裡我們也用模版做了,同樣模版是在專案目錄下https://github.com/Mikaelemmmm/go-zero-looklook/tree/main/deploy/goctl,pipline中構建指定這個模版即可

  2. ${credentialsId}要替換為你的具體憑據值,即【新增憑據】模組中的一串字串,我們之前配置的是gitlab-cert所以這裡就填寫gitlab-cert,如果你不是這個自己要更換,${gitUrl}需要替換為你程式碼的git倉庫地址,其他的${xxx}形式的變數無需修改,保持原樣即可。

  3. 這裡跟官方文件有一點點不一樣,由於我專案資料夾目錄不同,goctl生成的dockerfile檔案我手動做了點調整,在一個我不是在構建時候生成的dockerfile,是在建立專案時候就把dockerfile一起放在目錄下,這樣構建映象時候不需要goctl了

5、配置k8s拉取私有倉庫映象

k8s在預設情況下,只能拉取harbor映象倉庫的公有映象,如果拉取私有倉庫映象,則是會報 ErrImagePullImagePullBackOff 的錯誤

1、先在jenkins釋出機器登陸harbor

$ docker login 192.168.1.180:8077
$ Username: admin
$ Password:
Login Succeeded

2、在k8s中生成登陸harbor配置檔案

#檢視上一步登陸harbor生成的憑證
$ cat /root/.docker/config.json  
{
	"auths": {
		"192.168.1.180:8077": {
			"auth": "YWRtaW46SGFyYm9yMTIzNDU="
		}
}

3、對祕鑰檔案進行base64加密

$ cat /root/.docker/config.json  | base64 -w 0

ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuMTgwOjgwNzciOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=

4、建立docker-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: docker-login
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuMTgwOjgwNzciOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0=
$ kubectl create -f docker-secret.yaml -n go-zero-looklook

secret "docker-login" created

6、構建

我們進入首頁,點選idenity進入詳情頁

然後可以看到,上面我們配置好的identity服務,如下圖 ,點選“Build with Parameters”, 然後選擇rpc,點選“開始構建”

第一次構建在拉程式碼時候都會失敗,應該是初始化啥東西,再點一次就好了。

部署成功

同樣道理,去構建identity-api,再去配置usercenter服務 構建usercenter-rpc、構建usercenter-api,接著配置其他服務、構建即可,本次我們先只構建identity-api、identity-rpc、usercenter-rpc、usercenter-api給大家演示。

6、新增閘道器

因為我們的api服務通過goctl釋出在k8s中都會暴露nodeport埠,索引我們看下k8s中go-zero-looklook名稱空間下的service的nodeport埠服務,然後將nodeport配置在nignx即可。

本次我們獨立一臺虛擬機器在k8s之外,安裝nginx,將k8s後端api服務通過nodeport方式把埠暴露給nginx,然後nginx在配置中配置此api服務,這樣nginx就充當閘道器使用。

nginx的安裝就不再這裡多說了,記得一定要有auth_request模組,沒有的話自己去安裝。

nginx的配置

server{
    listen 8081;
    access_log /var/log/nginx/looklook.com_access.log;
    error_log /var/log/nginx//looklook.com_error.log;

    location /auth {
	    internal;
      proxy_set_header X-Original-URI $request_uri;
	    proxy_pass_request_body off;
	    proxy_set_header Content-Length "";
	    proxy_pass http://192.168.1.182:31001/identity/v1/verify/token;
    }

    location ~ /usercenter/ {
       auth_request /auth;
       auth_request_set $user $upstream_http_x_user;
       proxy_set_header x-user $user;

       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header REMOTE-HOST $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass http://192.168.1.182:31002;
   }

   location ~ /travel/ {
       auth_request /auth;
       auth_request_set $user $upstream_http_x_user;
       proxy_set_header x-user $user;

       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header REMOTE-HOST $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass http://192.168.1.182:31003;
   }

   location ~ /order/ {
       auth_request /auth;
       auth_request_set $user $upstream_http_x_user;
       proxy_set_header x-user $user;

       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header REMOTE-HOST $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass http://192.168.1.182:31004;
   }

   location ~ /payment/ {
       auth_request /auth;
       auth_request_set $user $upstream_http_x_user;
       proxy_set_header x-user $user;

       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header REMOTE-HOST $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass http://192.168.1.182:31005;
   }
}

如果是線上的話,應該配置多臺nignx保持高可用,在nignx前面還會有一個slb,你的域名包括https配置都應該解析到slb,在slb前面在有防火牆等這些。

8、結束語

至此,整個系列就結束了,整體架構圖應該如第一篇所展示,本系列希望能給你帶來幫助。

專案地址

https://github.com/zeromicro/go-zero

https://gitee.com/kevwan/go-zero

歡迎使用 go-zerostar 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 交流群 獲取社群群二維碼。