K8s部署Eureka集羣

在k8s集羣中通過CICD進行部署Eureka集羣

一、前言

普通後端如果想要同時起多個服務來進行負載均衡,可以通過部署Deployment並調整Pod的數量,然後交由Service來代理這些Pod
而對於Eureka而言,這樣做就沒那麼方便了,因爲Eureka之間還需要互相註冊,因此需要做一些特殊的改動。
主要用到了StatefulSetHeadless Service這兩個控制器

二、StatefulSet

這是一個用於管理有狀態程序的控制器,它在管理Pod時,確保每一個Pod有一個按順序增長的ID。它與Deployment相似,也是基於一個Pod模板進行管理其Pod,最大的不同在於
它始終給Pod分配不變的名稱。

1、使用場景

  • 穩定且唯一的網絡標識,Pod重新調度後並不會更改PodNameHostName,基於Headless Service實現
  • 穩定的持久化存儲,每個Pod始終對應屬於自己的存儲,基於PersistentVolumeClaimTemplate
  • 有序的增加(從0到N-1)、減少副本(從N-1到0)
  • 按順序的滾動更新

2、DNS格式

StatefulSet中每個Pod的DNS格式爲

StatefulSetName-{0..N-1}.ServiceName.namespace.svc.cluster.local
  • ServiceNameHeadless Service的名字
  • 0..N-1Pod所在的序號,從0開始到N-1
  • StatefulSetNameStatefulSet的名字
  • namespace爲命名空間,Headless Service和StatefulSet必須在相同的namespace
  • cluster.localCluster 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的界面,如果訪問失敗,那就要檢查下域名是否正確了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章