我們用一個系列來講解從需求到上線、從代碼到k8s部署、從日志到監控等各個方面的微服務完整實踐。
整個項目使用了go-zero開發的微服務,基本包含了go-zero以及相關go-zero作者開發的一些中間件,所用到的技術?;臼莋o-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://git@192.168.1.180:2222/root/go-zero-looklook.git']]])
}
}
stage('獲取commit_id') {
steps {
echo '獲取commit_id'
git credentialsId: 'gitlab-cert', url: 'ssh://git@192.168.1.180: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://git@192.168.1.180: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
}
}
}
}
非常重要?。?!
- 構建優化: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中構建指定這個模版即可
- 要替換為你的具體憑據值,即【添加憑據】模塊中的一串字符串,我們之前配置的是所以這里就填寫,如果你不是這個自己要更換,{gitUrl}需要替換為你代碼的git倉庫地址,其他的${xxx}形式的變量無需修改,保持原樣即可。
- 這里跟官方文檔有一點點不一樣,由于我項目文件夾目錄不同,goctl生成的dockerfile文件我手動做了點調整,在一個我不是在構建時候生成的dockerfile,是在創建項目時候就把dockerfile一起放在目錄下,這樣構建鏡像時候不需要goctl了
5、配置k8s拉取私有倉庫鏡像
k8s在默認情況下,只能拉取harbor鏡像倉庫的公有鏡像,如果拉取私有倉庫鏡像,則是會報 ErrImagePull 和 ImagePullBackOff 的錯誤
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
歡迎使用 go-zero 并 star 支持我們!