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的界面,如果访问失败,那就要检查下域名是否正确了


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