本文尝试部署kubernetes集群,并理解该组件能够做什么,什么时候使用。
部署集群 假设我们有3台设备,每台设备都已修改过hostname:
1 hostnamectl set-hostname xxxx
并已同步在/etc/hosts里配置了对应的ip hostname映射。
master、node01、node02
前置准备(此步骤在所有节点上做):
1 2 3 4 5 6 7 8 9 10 11 12 13 cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni EOF yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes yum install -y docker
环境准备,包括关闭selinux、关闭swap、关闭防火墙、打开IP forward、修改docker的cgroupfs驱动为systemd、准备docker-shim(此步骤在所有节点上做):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 setenforce 0 swapoff -a systemctl stop firewalld systemctl disable firewalld cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system cat <<EOF | sudo tee /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" } EOF wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.10/cri-dockerd-0.3.10.arm64.tgz tar -zxf cri-dockerd-0.3.10.arm64.tgz cd cri-dockerdinstall cri-dockerd /usr/bin git clone https://github.com/Mirantis/cri-dockerd.git cd cri-dockerdinstall packaging/systemd/* /etc/systemd/system systemctl daemon-reload systemctl restart docker systemctl start cri-docker.socket systemctl enable --now kubelet
我们现在在master节点上启动集群:
1 kubeadm init --apiserver-advertise-address=[网卡ip] --pod-network-cidr=10.224.0.0/16
配置.kube/config,否则无法查询集群信息:
1 2 3 mkdir ~/.kubecp /etc/kubernetes/admin.conf ~/.kube/configkubectl get pods --all-namespaces
此时有两个coredns pod应该是pending的,因为它在等待cni插件。
安装cni插件,这里选calico:
注意这里calico在arm上有bug,遵循官网的yml 会安装失败报libpcap.so找不到,跟calico版本有关,原因见该issue
1 2 3 4 5 6 kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml wget https://docs.projectcalico.org/manifests/custom-resources.yaml vim custom-resources.yaml kubectl create -f custom-resources.yaml
安装成功后观察coredns是否为running。
如果coredns出现错误,通过kubectl describe coredns-xxxx -n kube-system查到bind 53: permission denied错误,则需要做如下变更:
1 2 3 4 kubectl edit cm coredns -n kube-system
意思是监听1053,再转发到8.8.8.8:53地址。
修改后重启coredns:
1 2 kubectl delete pod coredns-xxxx -n kube-system kubectl delete pod coredns-xxxx -n kube-system
重启后应能正确运行。
剩下的就是join工作节点了:
1 2 3 4 5 6 kubeadm token create --print-join-command kubeadm join 170.70.226.121:6443 --token jalb9p.6os29537lon9befl --discovery-token-ca-cert-hash sha256:923a907a5fb070aad4d91f4e5ce6a5b8c55b8c1d6d6e326eadc8c95eaa8987d2 kubectl get nodes
应全部ready。
至此集群搭建完成。
使用集群 准备一个样例:
数据库部分不在kubernetes上部署,只准备服务部分。
服务采用spring cloud,分几段:
服务网关spring cloud gateway
具体处理业务的服务
服务网关将通过rpc调用具体处理业务的服务。
网关和具体服务分开为两个pod
为了接近生产配置,网关设置出2个副本(分散在2个node),具体服务也同样处理。
Gateway
gateway作用:
官方样例:https://spring.io/guides/gs/gateway
1 2 3 git clone https://github.com/spring-guides/gs-gateway.git cd gs-gateway/initial
编写简单的gateway处理,路由到httpbin.org(一个公共的实验站点)。
1 2 3 4 5 6 7 8 9 @Bean public RouteLocator myRoutes (RouteLocatorBuilder builder) { return builder.routes() .route(p -> p .path("/get" ) .filters(f -> f.addRequestHeader("Hello" , "World" )) .uri("http://httpbin.org:80" )) .build(); }
示例解释:代理httpbin.org/get请求,新增了一个Hello:World消息头字段。
这种gateway跟nginx的区别?nginx不能做吗?
gateway相对更灵活,可编程,内置有权限、服务熔断等功能,可以做的事情跟多些。
rpc服务
rpc服务采用阿里的sofa-rpc,示例下载:https://help.aliyun.com/document_detail/149866.html?spm=a2c4g.152618.0.0.754c480bbGsKic
rpc调用涉及client和server,server提供interface实现,client调用interface。这里隐含了client和server的工程内需分别放一个interface文件。
工程目录如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 . ├── myclient-app │ ├── app │ │ ├── endpoint │ │ │ ├── pom.xml │ │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ └── alipay │ │ │ │ └── samples │ │ │ │ └── rpc │ │ │ │ ├── SampleRestFacade.java │ │ │ │ └── SampleService.java │ │ │ └── resources │ │ └── web │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ └── alipay │ │ │ │ └── mytestsofa │ │ │ │ ├── ReferenceHolder.java │ │ │ │ └── SOFABootWebSpringApplication.java │ │ │ └── resources │ │ │ ├── config │ │ │ │ ├── application-dev.properties │ │ │ │ ├── application.properties │ │ │ │ └── application-test.properties │ │ │ ├── logback-spring.xml │ │ │ └── static │ │ │ └── index.html │ │ └── test │ │ └── java │ └── pom.xml └── myserver-app ├── app │ ├── endpoint │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ ├── java │ │ │ └── com │ │ │ └── alipay │ │ │ └── samples │ │ │ └── rpc │ │ │ ├── impl │ │ │ │ ├── SampleRestFacadeImpl.java │ │ │ │ └── SampleServiceImpl.java │ │ │ ├── SampleRestFacade.java │ │ │ └── SampleService.java │ │ └── resources │ │ └── META-INF │ │ └── sofa-rpc │ │ └── sofa-config.json │ └── web │ ├── pom.xml │ └── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── alipay │ │ │ └── mytestsofa │ │ │ └── SOFABootWebSpringApplication.java │ │ └── resources │ │ ├── config │ │ │ ├── application-dev.properties │ │ │ ├── application.properties │ │ │ └── application-test.properties │ │ ├── logback-spring.xml │ │ └── static │ │ └── index.html │ └── test │ └── java │ └── com │ └── alipay │ └── mytestsofa │ └── web └── pom.xml
本地编译需先配置~/.m2/settings.xml指向阿里maven仓库(central仓库是没有pom表描述的这些包的):https://help.aliyun.com/document_detail/133192.html?spm=a2c4g.149866.0.0.3a17480bTRbEmC
新版maven默认要求https,这里的settings源为http,可能会碰到网络问题,请修改external:https:*
中的https为dummy
编译好会得到两个可执行jar包,启动方式:
1 2 java -jar myserver-xxxx-executable.jar java -jar myclient-xxxx-executable.jar
rpc client集成gateway
思路,定义一个filter,从SampleService获取相关字段,然后concat到httpbin响应里。
这里碰到问题,sofaboot应用有自己的依赖,和spring cloud gateway依赖似乎有冲突,尝试集成二者存在包不匹配导致类找不到的情况。
这块作为遗留问题,以后有时间再解。
使用spring cloud
尝试做一次spring cloud组件集成,包括:
配置中心:spring cloud config
注册中心:spring cloud eureka
rest接口:spring cloud web
数据映射:mybatis
数据库:mysql
1、配置中心效果:
product和order服务从github上 读取配置,并本地运行。
config-repository/productService-dev.properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 spring.datasource.driver-class-name =com.mysql.jdbc.Driver spring.datasource.url =jdbc:mysql://127.0.0.1:3306/experiment?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false spring.datasource.username =root spring.datasource.password =123456 spring.datasource.type =com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.minimum-idle =5 spring.datasource.hikari.maximum-pool-size =15 spring.datasource.hikari.auto-commit =true spring.datasource.hikari.idle-timeout =30000 spring.datasource.hikari.pool-name =DatebookHikariCP spring.datasource.hikari.max-lifetime =1800000 spring.datasource.hikari.connection-timeout =30000 spring.datasource.hikari.connection-test-query =SELECT 1 mybatis.mapper-locations =classpath:mapper/*.xml
本地product配置:
1 2 3 4 5 6 spring.application.name =productService eureka.client.service-url.defaultZone =http://localhost:8764/eureka/ spring.cloud.config.discovery.enabled =true spring.cloud.config.discovery.service-id =CONFIGCENTER spring.cloud.config.profile =dev spring.config.import =configserver:http://localhost:8096
上述8096端口有配置中心服务在监听:
1 2 3 4 5 6 server.port =8096 spring.application.name =configCenter eureka.client.service-url.defaultZone =http://localhost:8764/eureka/ spring.cloud.config.server.git.uri =https://github.com/StaveWu/config-repository.git spring.cloud.config.server.git.username =stavewu spring.cloud.config.server.git.password =******
配置中心服务主要用到了spring cloud config组件Config Server,注解:@EnableConfigServer
product使用的是Config Client,无需注解。
这样就形成了一条从product -> config server:8096 -> github/config-repository
的通路。
config-repository里有好几个配置文件,product服务怎么知道要拿哪一个?
这里猜测是一种约定:基于spring.appliction.name + spring.cloud.config.profile命名的配置文件将被读取,product服务对应到productService-dev.properties。
2、mybatis效果:
在product配置文件里,通过mybatis.mapper-locations=classpath:mapper/*.xml
读取到位于resources/mapper下的配置文件;通过spring.datasource.url=jdbc:mysql://127.0.0.1:3306/experiment?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
连接到名为experiment的数据库实例,与配置文件配合形成数据库数据读取加载。