
Spring Cloud Kubernetes微服务实战与源码分析 专栏收录该内容,点击查看专栏更多内容原创 吴就业 314 0 2020-06-23
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/e00f3e21700d49edbc21369561773090
作者:吴就业
链接:https://wujiuye.com/article/e00f3e21700d49edbc21369561773090
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
本篇文章写于2020年06月23日,从公众号|掘金|CSDN手工同步过来(博客搬家),本篇为原创文章。
本篇文章由原来的两篇文章合并为一篇:
- 《搭建本地Kubernetes集群与部署微服务》
- 《将分布式项目sck-demo部署到本地kubernetes,以及实现版本升级和回滚》

在安装minikube之前需要先安装一个虚拟机,如VirtualBox、VMWare Fusion。
为什么要装虚拟机呢?因为安装minikube只是用来搭建Kubernetes集群的工具,而minikube是在虚拟机上搭建的Kubernetes集群。首次启动minikube的过程很慢,因为minikube需要下载安装Kubernetes所需要的镜像。
如果使用VMWare Fusion,在启动minikube时可能会遇到一些坑,作为初学者,我们肯定不想一开始就折腾,卡住学习的进度,因此笔者建议大家安装VirtualBox。
第一步:安装kubectl
brew install kubernetes-cli
第二步:安装虚拟机
VirtualBox的安装跳过。
第三步:安装minikube:
brew install minikube
启动minikube,由minikube在虚拟机上安装Kubernetes集群。
首次启动minikube需要指定虚拟机驱动--vm-driver,并指定拉取安装Kubernetes时需要拉取的一些镜像文件的仓库地址为阿里云提供的镜像仓库地址,如果你有vpn,那么可以不考虑。
minikube start --vm-driver=virtualbox \\
--image-mirror-country='cn' \\
--image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
每种虚拟机对应的--vm-driver的值可到官网了解,这里列出两种常用的:
VMWare Fusion: vmwarefusionVirtualBox: virtualbox
后续启动不需要再指定一大堆参数:
minikube start
电脑重启之后启动:
minikube start --image-mirror-country='cn' \\
--image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
查看状态:
minikube status

启动dashboard:
minikube dashboard

停止minikube:
minikube stop
首先确保本地机器上已经安装了VirtualBox、minikube、Docker、kubectl。
在mac上安装docker可下载dmg安装,非常简单,还提供一个Docker dashboard可视化界面。下载链接:https://download.docker.com/mac/stable/Docker.dmg
第一步:项目打包
执行 mvn clean package -DskipTests 构建打包服务。
第二步:构建应用程序镜像
执行 docker-compose build 在本地(或jenkins)构建镜像。
第三步:将镜像push到镜像仓库
执行 docker image tag 打标签,再将镜像push到docker hub,push之前需要先登陆。push到私有仓库也是一样的步骤。
第四步:配置kubectl
使用kubectl之前确保 ~/.kube/config 的配置已修改为Kubernetes服务提供的凭据。但使用minikube不需要配置,因为minikube在启动Kubernetes集群时就已经配置好了,但如果是使用阿里云的容器服务就需要修改配置。
第五步:配置secret(看情况,不是必须的步骤)
如果是使用私有的镜像仓库,则需要为kubernetes容器从私有镜像仓库拉取镜像提供secret。
kubectl create --namespace=default secret \\
docker-registry my-docker-reg-secret \\
--docker-server=registry.cn-shenzhen.aliyuncs.com \\
[email protected] \\
--docker-password=xxxxx \\
[email protected]
其中--namespace用于指定名称空间,因为不同名称空间下,secret是不共享的。
第六步:将服务部署到Kubernetes
执行 kubectl apply -f [配置文件] 部署服务。
例如:
kubectl apply -f demo-srv.yaml
接下来将一步步介绍如何将sck-demo整个项目部署到本地kubernetes,包括镜像升级、让服务可通过浏览器访问、回滚版本,以及调整minikube虚拟机的内存大小。
项目地址:https://github.com/wujiuye/share-projects/tree/master/sck-demo

先来说说如何调整minikube虚拟机的内存大小。默认的minikube虚拟机分配的内存很小,如果不调整大小,你会发现,pod一起动起来,要么一会挂掉,要么就是其它服务的pod挂掉。不过对sck-demo来说默认的内存大小是足够的。
minikube,则需要先删除minikube delete
cpu和内存大小 minikube start --image-mirror-country='cn' \\
--image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers' \\
--cpus 2 --memory 4g \\
--vm-driver=virtualbox
或者先修改配置,再执行minikube delete,再重新启动。
minikube config set memory 4096
建议:如果本地机器内存少于
8g,不建议在本地搞minikube,不然电脑会很卡。
为容器配置预估的应用需要消费的cpu资源和内存大小(resources项):

将项目打包,然后构建镜像,构建镜像时应该打上tag,标志着每个镜像的版本号,启动一个服务也应该明确地指定镜像的版本,而不是使用默认latest。
mvn clean package -DskipTests
minikube已经启动,确保使用minikube docker守护进程为使镜像自动存在,而不需要将镜像推送至远程仓库再拉取,可以使用与minikube vm相同的docker主机构建镜像。
eval $(minikube docker-env)
如果不再使用minikube主机时,可以通过运行eval $(minikube docker-env -u)来撤消此更改:
eval $(minikube docker-env -u)
minikube的docker守护进程构建镜像以sck-demo项目的其中一个模块为例:
docker build -t wujiuye/sck-demo-provider:v1.0.0 ./sck-demo-provider
命令参数说明:
-t: 构建镜像并打标签;wujiuye/sck-demo-provider:v1.0.0:镜像标签;./sck-demo-provider:Dockerfile文件所在目录同样步骤,将sck-demo-consumer构建为镜像。
Deployment与Service描述文件,这两个配置写在同一个yaml文件。以sck-demo-provider为例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: sck-demo-provider
namespace: default
spec:
# 副本数
replicas: 1
selector:
matchLabels:
app: sck-demo-provider
template:
metadata:
labels:
app: sck-demo-provider
env: dev
spec:
# 容器配置
containers:
- name: sck-demo-provider
image: wujiuye/sck-demo-provider:v1.0.0
# 镜像拉去策略:Always(总是拉取)、IfNotPresent(默认值,本地有则使用本地镜像,不拉取)、Never(只使用本地镜像,从不拉取)
imagePullPolicy: Never
ports:
- name: http-port
containerPort: 8080
# 环境变量,引用ConfigMap资源,sck-demo-common-config为通用环境变量配置
envFrom:
- configMapRef:
name: sck-demo-common-config
# 指定ServiceAccount,稍后创建
serviceAccountName: pod-configmap-sa
# 使用---分割配置
---
apiVersion: v1
kind: Service
metadata:
name: sck-demo-provider
namespace: default
spec:
selector:
app: sck-demo-provider
env: dev
ports:
- protocol: TCP
port: 80
targetPort: 8080
其中sck-demo-common-config的配置如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: sck-demo-common-config
namespace: default
data:
SPRING_PROFILES_ACTIVE: dev
SERVER_PORT: "8080"
sck-demo-common-config为通用环境变量配置,也是ConfigMap资源。
使用kubectl创建名为sck-demo-common-config的ConfigMap资源:
kubectl apply -f k8s/dev/config/sck-demo-common-config.yaml
使用kubectl创建sck-demo-provider服务的Deployment与Service:
kubectl apply -f k8s/dev/service/sck-demo-provider.yaml


sck-demo项目使用到动态配置,因此还需要为每个服务(使用到动态配置的服务)编写ConfigMap资源配置文件。以sck-demo-provider为例:
apiVersion: v1
kind: ConfigMap
metadata:
name: sck-demo-provider-config
namespace: default
data:
## 动态配置内容
application-dev.yml: |-
sck-demo:
message: for dev config map
使用kubectl创建ConfigMap:
kubectl apply -f k8s/dev/config/sck-demo-provider-config.yaml

ConfigMap资源配置时需要用到。创建一个ServiceAccount:
# 创建ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-configmap-sa
namespace: default
创建角色pod-configmap-read-role:
# 创建角色(pod级别)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-configmap-read-role
namespace: default
# 注册中心需要services的访问权限
rules:
- apiGroups: [""]
# 该角色可以访问的资源
resources: ["pods","configmaps","endpoints","services"]
# 限定能做哪些操作
verbs: ["get", "watch", "list"]
将ServiceAccount与角色绑定:
# 为指定ServiceAccount绑定角色
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-configmap-read-role-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-configmap-read-role
subjects:
- kind: ServiceAccount
name: pod-configmap-sa
namespace: default
将这三个文件放在同一个目录account,最后使用kubectl创建用户、角色、以及将用户与角色绑定:
kubectl apply -f k8s/dev/account

如果我们只是想测试sck-demo-consumer调用sck-demo-provider能否成功,我们可以选择只暴露sck-demo-consumer。由于动态配置是写在sck-demo-provider的,并且提供了api来验证动态配置是否生效,因此也需要将sck-demo-provider暴露到外部可访问。
修改sck-demo-provider与sck-demo-consumer的Service配置,将集群IP类型改为NodePort。
sck-demo-consumer.yaml
“`yaml
apiVersion: v1
kind: Service
metadata:
name: sck-demo-consumer
namespace: default
spec:
selector:
app: sck-demo-consumer
env: dev
ports:
* `sck-demo-provider.yaml`
yaml
apiVersion: v1
kind: Service
metadata:
name: sck-demo-provider
namespace: default
spec:
selector:
app: sck-demo-provider
env: dev
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: NodePort
“`更新Service:
kubectl apply -f k8s/dev/service
其中k8s/dev/service目录存放sck-demo项目的dev环境下所有服务的Deployment与Service配置的配置文件。
使用minikube service命令暴露服务,让本地可访问。
暴露sck-demo-consumer服务:
minikube service sck-demo-consumer

暴露sck-demo-provider服务:
minikube service sck-demo-provider

在浏览器访问http://192.168.99.103:30462/demo,验证服务是否调用成功,如果如下:

修改sck-demo-provider-config.yaml文件,或者直接在kubernetes dashboard修改,验证动态配置是否生效。

如图,我们将sck-demo.message修改为for dev config map yyyyy,修改完成后点击update,接着浏览器访问:http://192.168.99.103:31424/v1/config:

接收动态配置的bean:
@Component
@ConfigurationProperties(prefix = "sck-demo")
@RefreshScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class DemoProps {
private String message;
}
注意:在测试时,不要将DemoProps写到响应体,否则会报序列化异常,因为这是一个动态代理对象,我们在分析动态配置实现源码后再回过头来看就不难理解了。
在上一篇文章中,我们添加了监听动态配置刷新事件并打印日记的代码,因此,现在我们还可以使用kubectl logs查看Pod输出的日记:
kubectl logs pod的name

v1.0.1:
shell
docker build -t wujiuye/sck-demo-provider:v1.0.1 ./sck-demo-provider
对Deployment做一次升级
shell
kubectl set image deployment deployment名称 容器名称=镜像版本
如:
kubectl set image deployment sck-demo-provider sck-demo-provider=wujiuye/sck-demo-provider:v1.0.1
命令执行成功后,会启动新的Pod,当新的Pod启动成功后,旧的Pod会被移除。新Pod的描述文件容器配置部分将会更新为如下:
spec:
containers:
- name: sck-demo-provider
image: 'wujiuye/sck-demo-provider:v1.0.1'
以sck-demo-provider为例:
在更新Deployment时加上--record,记录本次执行的命令,以便后续查看历史记录时,能够看出每个版本都做了什么,能够判断需要回滚到哪个版本。
kubectl set image Deployment sck-demo-provider sck-demo-provider=wujiuye/sck-demo-provider:v1.0.3 --record
查看历史版本:
kubectl rollout history deployment sck-demo-provider --namespace=default
回滚到某个版本:
kubectl rollout undo deployment sck-demo-provider --to-revision=10 --namespace=default
--to-revision:指定回滚到哪个版本--namespace:名称空间sck-demo-provider:需要回滚的deployment的名称
如上图所示,回滚成功后,版本10就更新成新的版本号了。
通过-o wide查看deployment状态信息:
kubectl get deployment sck-demo-provider -o wide

查看replicaset每个版本的状态信息:
kubectl get replicaset

可使用revisionHistoryLimit控制ReplicaSet的历史版本保留数量,默认为10。

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

本篇介绍OpenFeign与Feign的关系、Feign底层实现原理、Ribbon是什么、Ribbon底层实现原理、Ribbon是如何实现失败重试的?
如果指定了URL,那么getOptional方法不会返回null,且返回的Client是LoadBalancerFeignClient,但不会抛出异常。如果不指定URL,则走负载均衡逻辑,走的是loadBalance方法,且抛出异常。
本篇我们将从一个简单的demo上手Spring Cloud kubernetes,当然,我们只用到Spring Cloud kubernetes的服务注册与发现、配置中心模块。
选择Spring Cloud Kubernetes意味着我们想要将服务部署到Kubernetes集群,Spring Cloud Kubernetes为我们实现了Spring Cloud的一些接口,让我们可以快速搭建Spring Cloud微服务项目框架,并能使用Kubernetes云原生服务。
作为开发者,只有足够了解容器技术,才能做好技术选型,以及开发部署在Kubernetes容器服务之上的应用应该要注意哪些问题。如果运维不了解代码,开发也不了解Kubernetes,谁能解决将服务迁移到Kubernetes上遇到的各种问题呢?
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。