k8s部署springcloud实际落地操作 在我的这篇文章中,我介绍了工作中实际落地的方案,大家都很感兴趣,想要更详细地介绍,这里我在本地用minikube给大家做一个演示。
演示的最终效果如下图,把网关部分和ingress去掉了,这里只演示核心,写了一个提供者和一个消费者,然后把他们注册到外部到注册中心nacos中,然后浏览器访问消费者的时候,消费者用注册中心获取的服务名远程去访问提供者的数据。
同时还会演示nacos配置中心动态修改配置文件的效果。从而达到了,k8s只部署应用服务的目的,而公共组件,数据库,配置中心,中间件等放到k8s外面部署。
具体为什么这样搞可以看我的这篇k8s部署springcloud实际落地操作文章,我认为对于我们来说是最适合的方案了。
minikube:我这里的演示环境用的minikube。相当于你们的k8s的部署环境
为了方便大家开发和体验Kubernetes,提供了可以在本地部署的Minikube,minikube安装部署方便,功能和真实环境的Kubernetes功能是一样的。
docker:编译和上传应用程序镜像需要用它,相关于你自己的开发环境。
镜像仓库:镜像仓库用来上传打包好的镜像,然后在其他服务器上可以pull下来,我的镜像仓库中心直接用的docker hub官方的。你可以用阿里的或者私有docker中心。
我的演示电脑是mac
代码说明
这里先看下provider以及consumer核心代码,如下:
provider的controller代码:
@RestController@Slf4j//实时更新配置中心的配置项@RefreshScopepublic class MainController {//注入配置文件中的配置项,从nacos配置中心实时拉取 @Value("${test}") private String test; @GetMapping("helloK8s") public String helloK8s() { String ip = getIp(); System.out.println(test); return "provider--helloK8s test:"+test+" ip: "+ip; } //获取本机ip地址 private String getIp(){ InetAddress ia=null; try { ia=InetAddress.getLocalHost(); String localname=ia.getHostName(); String localip=ia.getHostAddress(); System.out.println("本机名称是:"+ localname); System.out.println("本机的ip是 :"+localip); return localip; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; }}
consumer的controller代码:
@RestController@Slf4j//实时更新配置中心的配置项@RefreshScopepublic class ConsumerController { @Autowired private RestTemplate restTemplate; //注入配置文件中的配置项,从nacos配置中心实时拉取 @Value("${test}") private String test; @GetMapping("/echo/appName") public String echoProviderName(){ //通过nacos注册中心中的服务名first-provider去访问提供者api String url = "http://first-provider/helloK8s"; String res = restTemplate.getForObject(url,String.class); log.info("res is {}",res); return "consumer---config: " +test+" content:" + res; }}
然后就是pom docker打包上传的核心配置部分:
1.8wanglining1987test-k8sdocker-repositorydocker.iohttp://192.168.1.105:3375-Xms128m -Xmx128m/tmpHoxton.SR82.2.1.RELEASEcom.spotify docker-maven-plugin 1.2.0${docker.serverId}${docker.registry}${docker.host}${project.docker.name}/${image.name}:${project.version}java${project.version}${docker.volumes}${docker.java.opts}["sh","-c","java $JAVA_OPTS -jar /${project.build.finalName}.jar"]/${project.build.directory}${project.build.finalName}.jarremove-imagepackageremoveImage ${project.docker.name}/${image.name} ${project.version}latestremove-tag-imagepackageremoveImage ${docker.registry}/${project.docker.name}/${image.name} ${project.version}latestbuild-imagepackagebuild${project.docker.name}/${image.name}:${project.version}tag-imagepackagetag${project.docker.name}/${image.name}:${project.version} ${docker.registry}/${project.docker.name}/${image.name}:${project.version} tag-image-latestdeploytag${project.docker.name}/${image.name}:${project.version} ${docker.registry}/${project.docker.name}/${image.name}:latest push-imagedeploypush ${docker.registry}/${project.docker.name}/${image.name}:${project.version}
这里主要是用maven中docker的插件进行镜像的打包,并且上传到镜像中心。
里面的配置我不做过多讲解了,可以自行百度。我这里主要说明一点,里面的配置项
http://192.168.1.105:3375
这里面的地址配置的是访问本地docker deamon的地址,docker的原理其实就是当你执行docker命令的时候,它会把命令发送给docker deamon程序来执行具体的动作。
Daemon是Docker的守护进程,Docker Client通过命令行与Docker Damon通信,完成Docker相关操作
在mac上默认是访问不到docker deamon的,需要一个代理服务转发下,如下:
Docker代理服务(shipyard/docker-proxy)
这是一个非常轻量级的容器,它只是将请求从TCP转发到Docker监听的Unix套接字。
运行如下命令来开启代理转发:
docker run -p 3375:2375 -v /var/run/docker.sock:/var/run/docker.sock -d -e PORT=2375 shipyard/docker-proxy
然后你的代理地址就是本机ip+3375,配置到pom文件中即可。
第一步:编译应用程序打包成jar,并编译成docker镜像,然后push到docker仓库中心。
第一步点击package打包,maven插件会自动把代码打成jar包,然后把之前的docker同名镜像删除再重新build新的docker镜像。执行结果如下:
这里的wanglining1987/test-k8s:provider build出来的镜像
第二步点击push,会把上一步打包好的应用镜像上传到仓库中。执行结果如下:
然后同理对consumer工程也执行这个步骤,最终jar包镜像都上传到了docker镜像中心,如下图:
这两个镜像就是上面编译出来的。分别是消费者和生产者镜像。
第二步,启动minikube,并且启动dashboard
启动minikube,并指定阿里镜像中心
minikube start --registry-mirror=https://j3wvoj70.mirror.aliyuncs.com
启动dashboard,执行命令:minikube dashboard
执行结果如下:
执行成功后,会自动跳转到dashboard界面,如下图:
通过dashboard可以方便地管理k8s,比如操作Service,Deployment, pod等,每一步操作都会提示对应那个命令,很好用,提供了很大的方便。
第三步,编写k8s的Deplyment对应的yaml文件,来部署应用到Pod中
yaml文件如下:
apiVersion: apps/v1kind: Deploymentmetadata: name: first-deployment-2 labels: app: first-app-labelspec: # 启动三个实例 replicas: 3 selector: matchLabels: app: first-app template: metadata: labels: app: first-app spec: containers: - name: first-app # 指定要运行的镜像,启动后,会从镜像中心下载该镜像并运行 image: wanglining1987/test-k8s:provider ports: - containerPort: 8080---apiVersion: apps/v1kind: Deploymentmetadata: name: consumer labels: app: consumer-labelspec: replicas: 1 selector: matchLabels: app: consumer-app template: metadata: labels: app: consumer-app spec: containers: - name: consumer-app image: wanglining1987/test-k8s:consumer-2 ports: - containerPort: 8082
创建完成文件名:first-deployment.yaml
启动nacos
运行应用镜像之前,记住先把nacos注册中心启动一下,不然就启动失败了,按照最开始的架构,注册中心是放到k8s外面运行,直接在本机电脑上运行启动nacos即可,不放到k8s中。
运行起来后,可以通过 http://localhost:8848/nacos/去访问nacos管理页面
运行镜像
然后执行如下命令,来把provider和consumer对应的镜像运行起来。
kubectl create -f first-deployment.yaml
运行起来后,在dashboard中看下效果,如下:
上面两个是启动起来的Deployment。点进去可以查看Deployment的详情,具体什么是Deployment就不展开说了,k8s里的概念,有兴趣去百度即可。这里也可以用命令去查看运行的Deployment,没有dashboard来的方便直接。
然后可以去查看Deployment部署的Pod,并且去查看Pod内应用运行的日志:
这里consumer运行了一个实例,provider运行了三个,这个实例数量,也是在上面的first-deployment.yaml文件中指定了。查看pod日志:
还是很方便的。可以看到应用起来了。
检查下nacos注册中心中是否已经注册上应用了,打开注册中心管理界面地址如下图:
可以看到有两个服务注册进去了first-provider和first-consumer,其中first-provider是三个实例,first-consumer是一个,跟前面配置的一致,在进去看下服务详情如下:
观察其IP地址,是k8s分配的内部地址,成功注册到外部的nacos上了,这里需要注意,k8s内的服务是可以访问k8s外部的ip地址的,只是外部的机器没有办法访问k8s内部的服务ip。
剩下最后一步了就是通过浏览器访问下消费者,看看能不能成功调用提供者接口,并返回结果到页面。
接下来要通过浏览器访问消费者,怎么访问呢?直接通过ip肯定不行,都是k8s内部的ip地址。
k8s解决了这个问题,都很多方法,可以是ingress,或者直接通过Service直接暴露出来。
这里简单把k8s官网的对service和pod定义拉下来,供参考:
Kubernetes Pods是有生命周期的。他们可以被创建,而且销毁不会再启动。 如果您使用Deployment来运行您的应用程序,则它可以动态创建和销毁 Pod。
一个Kubernetes的Service是一种抽象,它定义了一组Pods的逻辑集合和一个用于访问它们的策略 - 有的时候被称之为微服务。一个Service的目标Pod集合通常是由Label Selector 来决定的(下面有讲一个没有选择器的Service 有什么用处)。
举个例子,想象一个处理图片的后端运行了三个副本。这些副本都是可以替代的 - 前端不关心它们使用的是哪一个后端。尽管实际组成后端集合的Pod可能会变化,前端的客户端却不需要知道这个变化,也不需要自己有一个列表来记录这些后端服务。Service抽象能让你达到这种解耦。
对于熟悉springcloud微服务的,你就可以把k8s里的这个service和springcloud中的微服务概念去对应,道理是差不多的。k8s可以把service通过几种方式暴露出来,供外部访问,有四种方式如下:
ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType。
NodePort:通过每个节点上的 IP +静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 :,你可以从集群的外部访问一个 NodePort 服务。
LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型的代理。
这里选择最方便的NodePort方式,对应的Service yaml文件如下:
apiVersion: v1kind: Servicemetadata: name: consumer-service labels: app: consumer-app role: masterspec: type: NodePort#type: LoadBalancer ports: - port: 8083 targetPort: 8082 selector: # 这里的consumer-app会去匹配first-deployment.yaml的template部分定义的lable名 # 从而和具体的Pod关联起来了 app: consumer-app
命名:first-service.yaml,然后通过如下命令启动Service
kubectl create -f first-service.yaml
启动成功后,查看dashboard,如下:
可以看到consumer-service启动成功,跟yaml中定义的一致。
然后运行命令:
$minikube service consumer-service --urlhttp://192.168.64.2:32376
会把访问服务的ip地址和端口打印出来,通过http://192.168.64.2:32376就可以访问到consumer-service后面实际对应的应用程序了。
在最开始consumer项目对应的controller中定义了api /echo/appName,把路径拼起来,去浏览器访问:http://192.168.64.2:32376/echo/appName
对照前面provider和consumer代码看下,k8s内部的consumer通过外部的nacos注册中的服务名成功的调用到了provider的接口,并打印输出接口。
代码中还把配置文件中的test变量打印了出来,这个主要是为了测试nacos配置中心的变化能不能更新到k8s内部的服务中的。如下部分
@Value("${test}")private String test;
nacos配置中心中的配置:
文件内容
打印结果中,标红部分是配置中心的配置,也是成功了。
consumer---config: ffff content:provider--helloK8s test:eeeaafff ip: 172.17.0.7
我们的方案使用springcloud全部组件和特性,对开发者开发调试更容易,开发方式也更熟悉。部署的时候只需要部署应用部分,发挥k8s部署扩容方便的优势。结合了两者共同的优势
--后续我会持续输出高质量的文章,我工作中更多实战的东西,以及源码部分的讲解,希望大家多多关注 关注+私信给代码,希望多多支持