在k8s集羣中通過CICD進行部署Eureka集羣
一、前言
普通後端如果想要同時起多個服務來進行負載均衡
,可以通過部署Deployment
並調整Pod
的數量,然後交由Service
來代理這些Pod
,
而對於Eureka
而言,這樣做就沒那麼方便了,因爲Eureka
之間還需要互相註冊
,因此需要做一些特殊的改動。
主要用到了StatefulSet
和Headless Service
這兩個控制器
二、StatefulSet
這是一個用於管理有狀態程序的控制器,它在管理Pod
時,確保每一個Pod
有一個按順序增長的ID
。它與Deployment
相似,也是基於一個Pod
模板進行管理其Pod
,最大的不同在於
它始終給Pod
分配不變的名稱。
1、使用場景
- 穩定且唯一的網絡標識,
Pod
重新調度後並不會更改PodName
和HostName
,基於Headless Service
實現 - 穩定的持久化存儲,每個
Pod
始終對應屬於自己的存儲,基於PersistentVolumeClaimTemplate
- 有序的增加(從0到N-1)、減少副本(從N-1到0)
- 按順序的滾動更新
2、DNS格式
StatefulSet
中每個Pod
的DNS格式爲
StatefulSetName-{0..N-1}.ServiceName.namespace.svc.cluster.local
-
ServiceName
爲Headless Service
的名字 -
0..N-1
爲Pod
所在的序號,從0
開始到N-1
-
StatefulSetName
爲StatefulSet
的名字 -
namespace
爲命名空間,Headless Service和StatefulSet必須在相同的namespace
-
cluster.local
爲Cluster Domain
如果Pod在同一個命名空間內,可以省略.namespace.svc.cluster.local
3、HeadLess Service
HeadLess Service
和普通的Service
最大的區別在於它代理的每一個Pod都會有對應一個域名
(上節提到的DNS格式),在實際使用它的時候,我們需要將它的clusterIP
屬性設置爲None
來表明它是一個HeadLess Service
三、搭建Eureka項目
1、創建項目
這裏自行創建Eureka項目哦,這裏不做演示
2、啓動類增加註解
/**
* 增加@EnableEurekaServer來開啓Eureka服務
* @author Gjing
*/
@EnableEurekaServer
@SpringBootApplication
public class K8sEurekaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(K8sEurekaDemoApplication.class, args);
}
}
3、配置文件
這裏使用了變量的形式設置配置的值,這樣就可以根據不同的環境來分別配置了。如果對變量的使用不熟悉的話建議惡補一下SpringBoot項目在Yaml文件使用變量。這裏只是演示的配置,在實際使用時
根據業務需求來合理配置
server:
port: ${EUREKA_HOST:8761}
spring:
application:
name: ${SERVER_NAME:k8s-eureka-demo}
eureka:
client:
# 從eureka獲取註冊信息
fetch-registry: ${FETCH_EUREKA:false}
# 註冊自己
register-with-eureka: ${REGISTER_EUREKA:false}
# 服務註冊中心地址
service-url:
defaultZone: ${EUREKA_URL:http://localhost:8761/eureka/}
instance:
# 當前實例的主機名稱
hostname: ${HOST_NAME:localhost}
server:
# 關閉安全模式
enable-self-preservation: false
4、Dockerfile
FROM openjdk:8-jdk
COPY target/*.jar app.jar
ENTRYPOINT java $JAVA_OPTS -jar $CONFIG app.jar
5、CI腳本文件
不是很熟悉CI寫法的建議先看閱讀:SpringBoot使用CICD
before_script:
- export IMAGE_FULL_NAME=${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHA}
stages:
- compile
- build
- run
variables:
MAVEN_REPO: "/.m2"
PROJECT_NAME: "k8s-eureka"
K8S_FILE: "eureka-k8s.yml"
compile:
stage: compile
image: 172.20.9.4:5001/gjing/maven:1.0
only:
- master
tags:
- pub
script:
- mvn -Dmaven.repo.local=$MAVEN_REPO clean package -Dmaven.test.skip=true
artifacts:
name: $PROJECT
expire_in: 1week
paths:
- target/*.jar
build:
stage: build
image: docker:stable
only:
- master
tags:
- pub
script:
- docker login --username $CI_REGISTRY_USER --password $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_FULL_NAME .
- docker push $IMAGE_FULL_NAME
- docker rmi -f $IMAGE_FULL_NAME
run:
stage: run
image: roffe/kubectl
only:
- master
tags:
- pub
variables:
PROJECT_PORT: 8761
PROJECT_NAMESPACE: gj # 命名空間需要提前在k8s中創建好
script:
# 配置 kubectl, ${KUBE_CONFIG}這個變量會在下面發佈的章節介紹如何配置
- mkdir -p /root/.kube
- echo ${KUBE_CONFIG} | base64 -d > /root/.kube/config
- export KUBECONFIG=/root/.kube/config
- kubectl version
# 修改k8s文件裏的一些變量
- sed -i "s#{PROJECT_NAME}#$PROJECT_NAME#g;
s#{PROJECT_PORT}#$PROJECT_PORT#g;
s#{PROJECT_NAMESPACE}#$PROJECT_NAMESPACE#g;
s#{PROJECT_IMAGE}#$IMAGE_FULL_NAME#g" $K8S_FILE
# 創建
- kubectl apply -f $K8S_FILE
6、項目的k8s文件
創建一個名爲eureka-k8s.yml
文件
# 定義一個ConfigMap用於存儲eureka的註冊中心地址
apiVersion: v1 # 版本號
kind: ConfigMap # 類型
metadata: # 定義元數據,名稱與命名空間
name: eureka-host
namespace: {PROJECT_NAMESPACE}
data: # 定義這個ConfigMap要存儲的數據
registry_url: http://{PROJECT_NAME}-0.{PROJECT_NAME}:{PROJECT_PORT}/eureka/,http://{PROJECT_NAME}-1.{PROJECT_NAME}:{PROJECT_PORT}/eureka/,http://{PROJECT_NAME}-2.{PROJECT_NAME}:{PROJECT_PORT}/eureka/
--- # 定義service
apiVersion: v1
kind: Service
metadata: # service的元數據,包含名稱、命名空間、標籤
name: {PROJECT_NAME}
namespace: {PROJECT_NAMESPACE}
labels:
app: {PROJECT_NAME}
spec: # 定義屬性
selector: # 需要代理的pod的標籤
app: {PROJECT_NAME}
ports: # service的端口
- port: {PROJECT_PORT}
name: {PROJECT_NAME}
clusterIP: None # 設置爲None,表示我們這是一個Headless Service
--- # 定義一個StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata: # 定義元數據,名稱與命名空間
name: {PROJECT_NAME}
namespace: {PROJECT_NAMESPACE}
spec:
replicas: 3 # 副本數
serviceName: {PROJECT_NAME} # 服務名
selector:
matchLabels: # 匹配下方的template中定義的label
app: {PROJECT_NAME}
template: # 定義pod的模板
metadata: # 模板的元數據
labels:
app: {PROJECT_NAME}
spec: # 定義模板的屬性
containers:
- name: {PROJECT_NAME}
image: {PROJECT_IMAGE}
ports:
- containerPort: {PROJECT_PORT}
readinessProbe: # 就緒檢查
httpGet:
path: /actuator/health
port: {PROJECT_PORT}
failureThreshold: 3 # 探測失敗的重試次數,如果超過3次了沒成功就認定爲pod是失敗的狀態
initialDelaySeconds: 60 # pod啓動延遲多久進行一次檢查
periodSeconds: 10 # 檢測的時間間隔
successThreshold: 1 # 只要一次成功就認爲pod是正常的
timeoutSeconds: 10 # 檢測的超時時間,如果超時了就認爲是失敗的一個狀態
env: # 配置環境變量,傳遞給項目的配置文件
- name: EUREKA_HOST
value: "{PROJECT_PORT}"
- name: SERVER_NAME
value: {PROJECT_NAME}
- name: FETCH_EUREKA
value: "true"
- name: REGISTER_EUREKA
value: "true"
- name: EUREKA_URL
valueFrom:
configMapKeyRef:
name: eureka-host
key: registry_url
- name: HOST_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
這時候我們就所有的準備工作都完成了
四、發佈
由於我們配了CI文件,那麼當我們代碼提交到Gitlab的時候,就會自動進行構建並啓動啦
1、配置KUBE_CONFIG變量
首先,我們先登陸到 k8s master節點服務器上,進入到/etc/kubernetes/
目錄,然後通過cat admin.conf
將這個文件的內容輸出到控制檯,最後將複製出來的內容先保存到
自己電腦的文本編輯器中,然後修改紅色框中的地址,將dns
修改爲你的ApiServer
的IP,如果是多master的話就是填寫ApiServer的LoadBalance IP了
然後我們複製修改後的所有內容,到瀏覽器隨便搜索一個在線的base64加密工具將內容進行加密。隨後,我們來到GitLab,進到具體項目或者項目組裏,點擊下方圖中的選項
點擊後進到下方頁面並添加變量,注意:鍵
要和你ci裏面寫的保持一致,值
的話就是剛剛加密後的內容了
最好將此變量配置在項目組中,這樣該項目組的所有項目都會繼承該變量
2、提交
上面已經配置了KUBE_CONFIG
變量了,這時候我們就可以直接提交代碼到GitLab啦,提交成功後就可以在GitLab項目左側的CICD選項中看到流水線在執行
當三個階段都打勾了就說明執行成功啦,如果出現了錯誤,那就可以點擊指定階段進去查看下錯誤日誌進行鍼對性修改了
這時我們可以去master服務器上執行命令查看下pod啓動成功沒
可以看到三個Pod
都是running狀態了,這時我們也可以通過kubectl logs -f k8s-eureka-0 -n gj
命令進行查看下其中一個Pod
的日誌,這裏我們可以看到Eureka
已經成功起來了
3、訪問
通過第二步,我們通過命令查看已經啓動成功了三個Eureka
副本,這時候,如果我們想通過瀏覽器訪問怎麼辦呢,這時候就需要定義一個Ingress
了,我們創建eureka-ingress.yml
文件,內容如下
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {PROJECT_NAME} # 這裏你自己定義Ingress的名稱
namespace: {PROJECT_NAMESPACE} # 這裏是命名空間,要與Eureka所在的命名空間一樣
spec:
rules:
- host: eureka.snowbd.onesport.com.cn # 這裏更改爲你的域名
http:
paths:
- backend:
serviceName: {PROJECT_NAME} # 指定後端的Service,也就是Eureka的Service
servicePort: {PROJECT_PORT} # Service端口
定義好後通過kubectl apply -f eureka-ingress.yml
命令進行構建,構建成功後我們可以通過kubectl get ingress -n gj
查看到剛剛構建的Ingress
我們通過剛剛配置的域名使用瀏覽器訪問一下Eureka
的界面,如果訪問失敗,那就要檢查下域名是否正確了