在上两个章节,分别讲述了基础环境的安装以及环境的测试环节,我们也可以理解一个持续集成的环境,那么在此正式进入我们的最终目标,实现整个大框架,将我们的具有生产能力的应用部署到私有Kubernetes集群中来,那么具体搭建Kuberentes环境就不在此赘述,因为机器的内存较小的原因,原本打算开三个节点的Kubernetes,发现实际情况不允许,Gitlab和Harbor服务器台耗费内存,那么带来的另一个原因就是,我们的应用程序多活可能也比较吃力,这里根据实际情况来确定某应用的副本吧;

接下来就正式进入实践环节,对于SpringCloud项目还有一个特点,任何应用向eureka注册,默认是通过主机名来注册的,这不符合我们的需要,因为在Pod内部是无法访问通过主机名来实现Pod访问的,所以此时我们需要修改我们是SpringCloud项目,将其注册方式修改为IP注册,直接利用IP向eureka注册,具体配置方式,在下面会讲到;

eureka

在此主要是说我们的eureka这个项目如何实现持续集成的,首先我们需要知道一个问题,对于SpringCloud项目来讲,对于eureka是个特殊的应用,它是一个无状态应用,但是因为其独有的特性,也就是说其他的任何微服务都需要与其进行注册,所以在此,我们需要使用两种控制器,一种的StateFulSet、Deployment,对于我们的eureka则使用StateFulSet,来让其在Pod重建的时候保证其PodName不发生变化;

Kubernetes预配置

在正式部署之前,我们需要做一些预配置,比如Namespace、ServiceAccount资源也最好事先去创建;

# 创建一个springcloud的Namespace,作为该项目的命名空间[root@node1 ~]# cat springcloud_ns.yamlapiVersion: v1kind: Namespacemetadata:  name: springcloud[root@node1 ~]# kubectl apply -f springcloud_ns.yaml

# 创建一个ServiceAccount,并使其能够管理springcloud这个命名空间[root@node1 ~]# cat springcloud_sa.yamlapiVersion: v1kind: ServiceAccountmetadata:  name: spring  namespace: springcloud---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:  name: springcloud-clusterrolebinding  namespace: springcloudroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: cluster-adminsubjects:  - kind: ServiceAccount    name: spring    namespace: springcloud[root@node1 ~]# kubectl apply -f springcloud_sa.yaml# 获取该ServiceAccount的token[root@node1 ~]# kubectl describe secrets -n springcloud $(kubectl describe sa -n springcloud spring|grep '^Tokens'|awk '{print $2}')|awk '/^token/{print $2}'...

eureka配置更新

因为eureka之间也是会相互注册的,所以对于eureka也需要修改其注册地址为现在所有可用的eureka的地址,在后面我们将eureka的副本设为两个,所以这里注册地址也需要写两个,然后还需要修改其配置为IP注册,这样才能让各应用之间互相连通;

# 将eureka的代码clone下来[root@node4 ~]# git clone http://192.168.1.64/SpringCloud/eureka.git[root@node4 ~]# cd eureka/[root@node4 eureka]# cat src/main/resources/application.yml spring:  application:    name: eurekaserver:  port: 6210eureka:  instance:    prefer-ip-address: true  # 修改为IP注册    hostname: eureka  client:    registerWithEureka: true #true表示向注册中心注册自己。    fetchRegistry: false    serviceUrl:  #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务      defaultZone: http://eureka-0.eureka-svc.springcloud.svc.cluster.local:6210/eureka/,http://eureka-1.eureka-svc.springcloud.svc.cluster.local:6210/eureka/  # 配置两个eureka的注册地址# 提交到主干[root@node4 eureka]# git add *[root@node4 eureka]# git commit -m 'edit config'[root@node4 eureka]# git push origin master此处修改了配置,别忘记重新打包上传到我们的Harbor

修改Docker配置

我们的Kubernetes主机之上的docker daemon也需要修改一些配置,主要是因为我们的Harbor仓库的非安全的,所以需要在每台Kubernetes的工作节点配置如下配置;

注意:每台Kuberentes集群的工作节点都需要配置

[root@node1 ~]# cat > /etc/docker/daemon.json << EOF{    "registry-mirrors": ["https://owcyje1z.mirror.aliyuncs.com"],    "insecure-registries":["http://192.168.1.64:8181"]}EOF
[root@node1 ~]# systemctl daemon-reload[root@node1 ~]# systemctl restart docker

Harbor认证

因为我们的Harbor仓库并不是公开访问的,那么此时,我们的Kubernetes在pull镜像的时候有会碰到用户认证的问题,所以我们需要实现配置一个认证的Secret;

首先,我们在Kubernetes主节点上登录一遍,生成registry认证文件

[root@node1 ~]# docker login 192.168.1.64:8181 [root@node1 ~]# cat /root/.docker/config.json {        "auths": {                "192.168.1.64:8181": {                        "auth": "YWRtaW46Y2FpY2hhbmdlbg=="                }        },        "HttpHeaders": {                "User-Agent": "Docker-Client/19.03.8 (linux)"        }}# 得到该文件的base64密文[root@node1 ~]# base64 -w 0 /root/.docker/config.json ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuNjQ6ODE4MSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZZMkZwWTJoaGJtZGxiZz09IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=# 基于认证文件来创建Secret[root@node1 ~]# cat registry_auth.yamlapiVersion: v1kind: Secretmetadata:  name: registry  namespace: springclouddata:  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjEuNjQ6ODE4MSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZZMkZwWTJoaGJtZGxiZz09IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=  # 上面的base64的密文type: kubernetes.io/dockerconfigjson

配置清单

我们需要预先将eureka的配置清单给做出来,并且将其上传到我们的eureka仓库,具体如下;

# 将eureka的代码clone下来[root@node4 ~]# git clone http://192.168.1.64/SpringCloud/eureka.git[root@node4 ~]# cd eureka/[root@node4 eureka]# cat > eureka.yaml << EOFapiVersion: apps/v1kind: StatefulSetmetadata:  name: eureka  labels:    app: eureka  annotations:    author: cce  namespace: springcloudspec:  serviceName: eureka-svc  replicas: 2  template:    metadata:      name: eureka-pod      namespace: springcloud      labels:        app: eureka    spec:      imagePullSecrets:        - name: registry      containers:        - name: eureka-container          image: 192.168.1.64:8181/springcloud/eureka:4          imagePullPolicy: IfNotPresent          livenessProbe:  # 配置健康状态检查            initialDelaySeconds: 3            successThreshold: 1            timeoutSeconds: 10            failureThreshold: 3            httpGet:              port: 6210              scheme: HTTP      restartPolicy: Always  selector:    matchLabels:      app: eureka---apiVersion: v1kind: Servicemetadata:  name: eureka-svc  namespace: springcloudspec:  selector:    app: eureka  ports:    - name: http      protocol: TCP      port: 6210      targetPort: 6210  clusterIP: None   # 无头Service---apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: springcloud-ingress  namespace: springcloudspec:  rules:    - host: eureka.springcloud.com # 记得将其加入hosts文件 192.168.1.61 eureka.springcloud.com      http:        paths:          - backend:              serviceName: eureka-svc              servicePort: 6210            path: /EOF

[root@node4 eureka]# git add *[root@node4 eureka]# git commit -m 'add kubernetes config'[root@node4 eureka]# git push origin master# 第一次部署的时候先手动部署,但是别忘记了上面做了很多修改,此时需要重新构建下Jenkins,重新生成新的镜像[root@node1 ~]# kubectl apply -f eureka.yaml[root@node1 ~]# kubectl get all -n springcloud NAME           READY   STATUS    RESTARTS   AGEpod/eureka-0   1/1     Running   0          3m10spod/eureka-1   1/1     Running   0          2m56s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGEservice/eureka-svc   ClusterIP   None         <none>        6210/TCP   3m10sNAME                      READY   AGEstatefulset.apps/eureka   2/2     3m10s

# 测试连通性[root@node1 ~]# kubectl exec -it -n springcloud eureka-0 sh/ # wget -S -O /dev/null -q http://eureka-0.eureka-svc.springcloud.svc.cluster.local:6210  # 第一个eureka正常  HTTP/1.1 200  Content-Type: text/html;charset=UTF-8  Content-Language: en-US  Transfer-Encoding: chunked  Date: Wed, 22 Apr 2020 04:28:12 GMT  Connection: close/ # wget -S -O /dev/null -q http://eureka-1.eureka-svc.springcloud.svc.cluster.local:6210 第一个eureka访问第二个eureka正常  HTTP/1.1 200  Content-Type: text/html;charset=UTF-8  Content-Language: en-US  Transfer-Encoding: chunked  Date: Wed, 22 Apr 2020 04:28:16 GMT  Connection: close

测试访问

好了,现在我们的eureka已经手动部署完成,接下来就来测试下eureka是否能够正常访问,因为我们使用的是内部域名所以需要先添加hosts解析

添加hosts解析


测试访问eureka是否部署成功

部署脚本

此处并非进行最后的应用部署,只是测试行的利用Python来调通Kubernetes集群,并且直接使用Python来远程管理集群,为最后一步应用部署做基础;

# 找到上面创建的ServiceAccount的token[root@node1 ~]# kubectl describe secrets -n springcloud $(kubectl describe sa -n springcloud spring|grep '^Tokens'|awk '{print $2}')|awk '/^token/{print $2}'...# 该token就可以作为我们管理这个springcloud命名空间的资源了,先测试下是否能够连通

在原有的持续集成的脚本之上附加一项持续部署的到Kubernetes的代码,实现持续部署



#!/usr/bin/env python3# -*- coding: utf-8 -*-# @Time    : 2020/4/15 23:43# @Author  : CaiChangEn# @Email   : mail0426@163.com# @Software: PyCharmimport docker, os, shutil, time, kubernetes

registry = '192.168.1.64:8181'project = 'springcloud'sitename = 'eureka'webfile = 'eureka.jar'sts_name = 'eureka'sts_namespace = 'springcloud'

class Deploy(object):    def __init__(self, rep, pro, name, file, sname, snamespace):        '''        :param rep: docker仓库地址(Harbor为例);        :param pro: 仓库的项目名称(Harbor为例)        :param name: 仓库的镜像名称;        :param file: 对于SpringCloud项目编译成功后生成的jar包的名称;        '''        print('\033[1;31mStep1 Start initialization\033[0m')        StartTime = time.time()        self.KubernetesObj = kubernetes.client.Configuration()        self.KubernetesObj.host = 'https://192.168.1.61:6443'        self.KubernetesObj.verify_ssl = False        self.KubernetesObj.api_key[            'authorization'] = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IlVxTXN4dGI2UXRlNHFoWmNuSDluRzFLQllKRHVrN2tUVE16TEU2N3lKMVkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJzcHJpbmdjbG91ZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJzcHJpbmctdG9rZW4tbWh4enEiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic3ByaW5nIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmUzZWNlM2UtNGY2Mi00ZThhLWEzZWYtY2M5NmFlNTVmMjFkIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNwcmluZ2Nsb3VkOnNwcmluZyJ9.Qe-UOE9oT34VAlqeNIZuISznxn5nvnGcRvOsp5J7njcJgjXrGHkjGna-h9yBA4epQE6iJ1jgr80GboXNseMHZx8Ui6UuZXwR_GmRCuyziji1nDqRR2UqocQuTaXSKMGeHsa7F4L7gGytTcq9NlkeNAfGX6iTibD01bRjFCJGRxH9VGYKnng_Q89C1C_JmdLW3VLXOvecugd6xsP9CzktQjZB1CBZSuatehPHc3yjFzkKImP7d3W-y-OaYOK-5QSA5L4-IW10tJrlQC4ovwHVqKcVe1uLvWC3dSQkS5TMn3PELA2-r3De2J_h8xAcAgnFCI0gypJynssypmNpSa3nXg'        self.KubernetesObj.api_key_prefix['authorization'] = 'Bearer'        self.StsName = sname        self.StsNamespace = snamespace        self.DockerClientObj = docker.DockerClient()        self.WorkSpace = os.getenv('WORKSPACE')        self.BuildId = os.getenv('BUILD_ID')        self.Context = os.path.join(self.WorkSpace, 'context')        self.SrcDockerFile = os.path.join(self.WorkSpace, 'Dockerfile')        self.DestDockerFile = os.path.join(self.Context, 'Dockerfile')        self.WebSiteFile = os.path.join(self.WorkSpace, 'target', file)        self.BuildTag = os.path.join(rep, pro, name) + ':' + self.BuildId        self.Repository = os.path.join(rep, pro, name)        print('\033[1;32mStep1 Use Time %.3f\033[0m' % float(time.time() - StartTime))
   def createEnv(self):        '''        该方法主要是创建一些初始环境,提供Dockerfile和需要构建的上下文        '''        print('\033[1;31mStep2 create env\033[0m')        StartTime = time.time()        os.mkdir(self.Context)        shutil.move(self.WebSiteFile, self.Context)        shutil.move(self.SrcDockerFile, self.Context)        print('\033[1;32mStep2 Use Time %.3f\033[0m' % float(time.time() - StartTime))        return self.buildImage()



   def deleteImage(self):        '''        该方法主要是删除镜像,如果正在构建的镜像已在本地存在,那么先删除        '''        try:            self.DockerClientObj.images.remove(self.BuildTag)            print('\033[1;34mDeleted Image %s\033[0m' % (self.BuildTag))        except Exception:            pass



   def buildImage(self):        '''        该方法正式开始构建镜像,并且给镜像指定对应的tag,默认的tag为jenkins的BUILD_ID        '''        print('\033[1;31mStep3 Build Image\033[0m')        StartTime = time.time()        self.deleteImage()        ImageObj, BuildLog = self.DockerClientObj.images.build(path=self.Context, quiet=False,                                                               dockerfile=self.DestDockerFile,                                                               tag=self.BuildTag, rm=True,                                                               forcerm=True)        for Log in BuildLog:            print(Log)        print('\033[1;32mStep3 Use Time %.3f\033[0m' % float(time.time() - StartTime))        return self.pushImage()

   def pushImage(self):        '''        该方法主要是将镜像上传到私有仓库,此案例主要是基于http协议的harbor仓库        '''        print('\033[1;31mStep4 Push Image\033[0m')        StartTime = time.time()        PushLog = self.DockerClientObj.images.push(repository=self.Repository, tag=self.BuildId,                                                   auth_config={"username": "admin", "password": "caichangen"},                                                   decode=True)        print(PushLog, end='')        print('\033[1;32mStep4 Use Time %.3f\033[0m' % float(time.time() - StartTime))        self.deleteImage()        return self.deployKubernetes()

   def deployKubernetes(self):        print('\033[1;31mStep5 Deploy Kubernetes\033[0m')        StartTime = time.time()        api_instance = kubernetes.client.AppsV1Api(kubernetes.client.ApiClient(self.KubernetesObj))        sts_instance = api_instance.read_namespaced_stateful_set(name=self.StsName, namespace=self.StsNamespace)        sts_instance.spec.template.spec.containers[0].image=self.BuildTag        api_instance.patch_namespaced_stateful_set(name=self.StsName, namespace=self.StsNamespace,body=sts_instance)        print('\033[1;32mStep5 Deploy Kubernetes %.3f\n部署成功\033[0m' % float(time.time() - StartTime))        return None



deploy = Deploy(registry, project, sitename, webfile, sts_name, sts_namespace)deploy.createEnv()

正式部署


接下来就是正式的正式上线环节了,但是有一点别忘记了,镜像的tag是通过Jenkins的BUILDID来生成的;

可以看到我们的两个eureka副本的镜像tag也变成了Jenkins的BUILDID

[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:5"

收官测试


接下来做最后一次测试,eureka的收官之测;

查看创建的镜像

可以看到,我们的上线流程的切换着来

[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:5"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:5""192.168.1.64:8181/springcloud/eureka:6"[root@node1 ~]# kubectl get pods -n springcloud -o json|jq .items[].spec.containers[].image"192.168.1.64:8181/springcloud/eureka:6""192.168.1.64:8181/springcloud/eureka:6"

至此,整个eureka的部署已经完成,那么在下一个环节将结束整个SpingCloud项


©著作权归作者所有:来自51CTO博客作者mob604756edd67c的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 企业之战|Kubernetes持续集成实践
  2. 静态路由原理与配置学习笔记分享
  3. Promethus集群部署笔记:(五)安装并配置snmp_exporter
  4. 阿里测试环境运维及研发效率提升之道
  5. IP地址分类及网络配置方法和多网卡绑定技术应用
  6. 在Ubuntu系统上使用kubeadm部署v1.20版的Kubernetes集群
  7. 粉丝福利 | 秒 get 支付宝同款扫码组件
  8. 对linux配置文件的处理----grep&sed
  9. 多厂商***系列之十七:华为AR系列路由器 实现l2tp over ipsec ***

随机推荐

  1. android中自定义RadioButton
  2. 控件的间距为0
  3. Android中3种方法实现back键动作
  4. javafx for android or ios ?
  5. Android系统中设置TextView的行间距(非行
  6. Android学习笔记(二三): 多页显示-Flipper的
  7. android中activity的四种加载模式
  8. android知识链接汇总(3)
  9. 第一天
  10. Android UI开发第一篇――android的九宫