nacos + k8s部署springcloud微服务


k8s安装

参见

kubernetes 的安装与部署

https://www.jianshu.com/p/a4ec985977c2



常见错误

  1. 需要双核cpu
  2. Error downloading packages libnetfilter_cthelper

解决:手动安装 yum install -y libnetfilter_cthelper

  1. kubectl conflicts with file from package kubernetes-client

解决:yum remove kubernetes-client-1.5.2-0.7.git269f928.el7.centos.aarch64

  1. 无法启动k8s服务,先执行kubeadm init
kubeadm init 
--image-repository registry.aliyuncs.com/google_containers 
--apiserver-advertise-address=192.168.197.10 
--service-cidr=10.222.0.0/16 
--pod-network-cidr=10.244.0.0/16

提示如下:

Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.197.10:6443 --token g01ldy.ikqrqrp2pgm18t4y 
--discovery-token-ca-cert-hash sha256:62ce23cd9b76c5409fec58f4a2b37e083fefc0204386d2d95546fe0b02109b31

根据提示然后执行下列命令

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
#如果是root用户,执行下列命令
export KUBECONFIG=/etc/kubernetes/admin.conf
  1. 子节点加入k8s网络,token 有效时间是24小时,如果过来24小时那么需要刷新token

# 在master 主节点上运行命令,刷新 token

kubeadm token create --print-join-command

基本概念

Pod

pod并不等于容器。一个pod可以由多个容器组成。例如,Pod可以包括一个带有Node.js应用程序的容器和另一个向web服务器提供数据的容器。

pod有以下内容:

组成pod的所有容器都运行在同一台机器上,不能跨多个节点拆分。

Pod的Kubectl命令行操作

创建并运行Pod

#创建命名空间 dev

kubectl create ns dev

#创建pod

kubectl run my-nginx --image=nginx:latest --port=80 --namespace=dev

查询所有Pod的基本信息

kubectl get pods -n dev -o wide –w

查看Pod的详细信息

kubectl describe pod my-nginx -n dev

访问pod中容器提供的服务

curl 10.244.169.134:80

查看pod的日志

kubectl logs -f my-nginx -n dev

重启指定的Pod

kubectl delete pod my-nginx -n dev

删除后自动创建,达到重启效果

Pod的Kubectl配置文件操作

新建pod-nginx.yaml,内容如下:

[root@k8s-master ~]# vim pod-nginx.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  namespace: dev
spec:
  containers:
  - image: nginx:latest
    imagePullPolicy: IfNotPresent
    name: nginx-container
    ports: 
    - name: nginx-port
      containerPort: 80
      protocol: TCP
[root@k8s-master ~]#

通过命令式对象配置进行创建和删除

kubectl create -f pod-nginx.yaml

kubectl delete -f pod-nginx.yaml

Deployment

deployments资源类型位于一个副本集(ReplicaSet)之上,可以对其进行操作。换句话说,deployments为pods副本集提供更新。

Deployment的Kubectl命令行操作

创建指定名称的deployement

kubectl create deployment my-nginx --image=nginx -n dev

-n 指定命名空间

将deploy的一个pod拓展到4个pod

kubectl scale deployment my-nginx --replicas=4 -n dev

查看deployment的信息

kubectl get deploy -n dev

kubectl get pod -n dev

查看deployment的详细信息

kubectl describe deployment my-nginx -n dev

删除deployment

deployment控制器删除,deployment下的pod也会被删除

kubectl delete deployment my-nginx -n dev

Service

如果我们想要连接到pods,就需要创建一个Service。在Kubernetes中,Service是一组pods上的网络抽象。可以将其看作在集群上运行的一组pods。Kubernetes服务通常用于支持微服务体系结构。

服务类型

可以使用的服务类型如下:

ClusterIP:

通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的Service类型。ClusterIP类型的service创建时,k8s会通过etcd从可分配的IP池中分配一个IP,该IP全局唯一,且不可修改。所有访问该IP的请求,都会被iptables转发到后端的endpoints中。

NodePort:

通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。

LoadBalancer:

需要外部支持(GCP and Azure),用户访问service.spec.external-ip,该IP对应到一个外部负载均衡的vip,外部服务对这个vip的请求,会被loadbalancer通过健康检查和转发,发送到一个运行着该服务pod的node上,并同样通过nodePort里的端口映射,发送给容器。

ExternalName:

用户可以指定一个任意的名字,作为该service被解析的CNAME,这种类型的servcie不用指定clusterIP,因此kube-proxy不会管理这类service,这类service需要使用1.7版本以上的kubedns。

提供容器服务

对内提供服务

Pod的网络是K8s在物理机上建立了一层Overlay Network实现的,而且在网卡上能够看到这个网络的地址。但是Service是一个完全虚拟的网络层,并不会存在于任何网络设备上。它通过修改集群内部的路由规则,仅对集群内部有效。Deploment创建好应用之后,再为它生成一个Service对象。接下来就可以通过Service的域名访问到服务,形式是.,比如你有为Deployment的应用创建了一个名为portal的Service在默认的命名空间,那么集群内想要通过Http访问这个应用,就可以使用http://portal.default。

对外提供服务

StatefulSet

介绍

RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:

$(podname).(headless server name)

FQDN:$(podname).(headless server name).namespace.svc.cluster.local

特点

Pod一致性:包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个node节点无关;

稳定的次序:对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的;

稳定的网络:Pod的hostname模式为(statefulset名 称 ) (statefulset名称)-(statefulset名称) (序号);

稳定的存储:通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本,不会删除相关的卷。

headless service

为什么需要 headless service 无头服务?

在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在statefulset中要求必须是有序 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。而pod IP是变化的,所以是以Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。

常用信息

1. 常用命令

# 查看k8s 运行日志命令, 这个比较有用,在k8s 启动、kubeadm init、kubeadm join 阶段可以辅助分析问题。

journalctl -xefu kubelet

# 查看k8s驱动

systemctl show --property=Environment kubelet |cat

# 重启k8s

systemctl restart kubelet

# 启动k8s

systemctl start kubelet

# 停止k8s

systemctl stop kubelet

# 开机自启k8s

systemctl enable kubelet

# dashboard 获取token

kubectl describe secret admin-user -n kubernetes-dashboard

# kubeadm 重置, 有些时候我们在使用kubeadm init 命令时会报错,我们根据错误提示修复问题后需要重新进行 init 操作,因此需要进行reset重置

kubeadm reset

删除普通pod

#查看deployment

kubectl get deployment --all-namespaces

#删除deploymnet,pod随之删除

kubectl delete deployment nacos-operator

#缩容

kubectl scale deployment/nacos-operator --replicas=0 -n default

删除nacos pod

kubectl scale statefulset nacos --replicas=0

删除service

kubectl delete svc myapp nacos-operator

删除mysql

kubectl scale rc mysql --replicas=0

2. 环境信息

# k8s 安装目录
ll /etc/kubernetes/
总用量 32
-rw-------. 1 root root 5642 6月 28 15:19 admin.conf
-rw-------. 1 root root 5674 6月 28 15:19 controller-manager.conf
-rw-------. 1 root root 1986 6月 28 15:19 kubelet.conf
drwxr-xr-x. 2 root root 113 6月 28 15:19 manifests
drwxr-xr-x. 3 root root 4096 6月 28 15:19 pki
-rw-------. 1 root root 5618 6月 28 15:19 scheduler.conf
# 组件配置文件目录
ll /etc/kubernetes/manifests/
总用量 16
-rw-------. 1 root root 2310 6月 28 15:19 etcd.yaml
-rw-------. 1 root root 3378 6月 28 15:19 kube-apiserver.yaml
-rw-------. 1 root root 2879 6月 28 15:19 kube-controller-manager.yaml
-rw-------. 1 root root 1464 6月 28 15:19 kube-scheduler.yaml
# 自定义dashboard yaml文件目录
ll /opt/kube-dashboard/conf/
总用量 4
-rw-r--r--. 1 root root 1124 6月 29 08:41 admin-user-dashboard.yaml
ll /opt/apps/k8s/
总用量 4
-rw-r--r--. 1 root root 285 6月 29 08:25 k8s-dashboard.yaml

k8s部署 Ingress-nginx controller

什么是 Ingress

Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。Ingress 可以提供负载均衡

Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。

下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:

但是 仅创建 Ingress 资源本身没有任何效果,需要有对应的 Ingress 控制器 ,你可能需要部署 Ingress 控制器,例如 ingress-nginx。 你可以从许多 Ingress 控制器 中进行选择。

什么是 Ingress controller

为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。k8s官网维护了 3 个Ingress控制器

目前支持和维护 AWSGCENginx Ingress 控制器 ,本篇就拿 Ingress-nginx 作为控制器为例 讲解一下如何部署

部署 Ingress-nginx controller

部署过程参考《k8s 1.23版本安装Ingress-nginx》,要点如下:

镜像文件地址,改成国内镜像

Service Type改成NodePort

删除配置 externalTrafficPolicy: Local(不删除外部无法访问Ingress)

k8s部署springboot项目

创建springboot项目,并打包

@RestController
@RequestMapping
("/k8s")
@Slf4j
public class K8sDemoController {
@GetMapping("hello")
public String hello(String name) {
String msg = String.format("Hello: %s welcome to k8s", name);
log.info("【{}】", msg);
return msg;
}
}

编写Dockerfile

FROM openjdk:8

COPY ./target/test-k8s-demo-0.0.1-SNAPSHOT.jar /app/springboot-k8s-demo.jar

# 容器工作目录

# WORKDIR /usr/local

# 设置字符集

ENV LANG C.UTF-8

ENTRYPOINT ["java", "-jar" , "/app/springboot-k8s-demo.jar"]

打包镜像

为使用docker将/target/test-k8s-demo-0.0.1-SNAPSHOT.jar和Dockerfile上传到k8s某个节点(也可以是安装了docker的任何机器),执行下列命令

$ docker build -t boot-k8s-demo:v1 . #构建镜像

注意最后有个点,默认使用 “上下文目录(Context)下的名为Dockerfile 的文件作为 Dockerfile”,在此,即用当前路径的 Dockerfile 进行构建 。

把镜像 push 到对应的 阿里云仓库

浏览器访问https://cr.console.aliyun.com/cn-hangzhou/instance/

进入阿里云容器镜像服务,点击个人实例

点击镜像仓库菜单-创建镜像仓库按钮,创建k8s仓库

第一步仓库名称为k8s,仓库类型选择公开;第二部代码源选择本地仓库

可在访问凭证-设置固定密码设置访问密码

docker tag boot-k8s-demo:v1 registry.cn-hangzhou.aliyuncs.com/muxiaoshan/k8s:v1

docker login --username=xxxxxx registry.cn-hangzhou.aliyuncs.com

docker push registry.cn-hangzhou.aliyuncs.com/muxiaoshan/k8s:v1

编写 k8s deploy yaml 进行部署2个副本 + ingress 实现基本的负载均衡

apiVersion: apps/v1
kind: Deployment #部署
metadata:
  name: springboot-app
spec:
  replicas: 2 #2个副本
  selector:
    matchLabels:
      app: springboot-app
  template:
    metadata:
      labels:
        app: springboot-app
    spec:
      containers:
      - name: springboot-app
        image: registry.cn-hangzhou.aliyuncs.com/muxiaoshan/k8s:v1 #刚刚push到阿里云上的镜像地址
        ports:
        - containerPort: 20187 #springboot端口 
---
apiVersion: v1
kind: Service
metadata:
  name: springboot-app
spec:
  selector:
    app: springboot-app #选中上面的 Deployment
  ports:
  - port: 7003 #对外7003端口
    targetPort: 20187
--- 
#Ingress 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: springboot.demo.com
    http:
      paths:
      - path: /
        pathType: Prefix    # 前缀匹配
        backend:
          service:
            name: springboot-app
            port:
              number: 7003

kubectl 部署 deploy-springboot-k8s.yaml

kubectl apply -f deploy-springboot-k8s.yaml

访问请求路径 进行测试

先把 springboot.demo.com 域名添加到客户机hosts,转到k8s集群中任何一台机器皆可

172.10.10.10 springboot.demo.com

客户机浏览器访问http://springboot.demo.com:31972/k8s/hello?name=sam

k8s部署nacos(可选)

推荐将注册中心(包括nacos等)部署到k8s外,整个k8s集群重启时,各个微服务节点常因连接不到集群内的nacos而启动失败,而且集群内nacos管理的服务容易掉线。加上nacos为有状态服务,不建议部署到k8s,单独搭建nacos集群,方便管理与调试。《nacos官网集群部署说明》

参考《k8s1.23.5部署nacos持久化集群》,要点如下:

  1. 初始化外部数据库(数据库不部署到k8s)
  2. K8s configmap配置数据库连接
  3. 部署Headless Service,在k8s中通过StatefulSet和Headless Service(没有ClusterIP,无法负载均衡)为每个nacos实例生成一个唯一的dns地址
  4. 通过StatefulSet部署nacos。nacos镜像使用v2.1.1版本,默认的latest是v2.0.3版本,新增配置会出错
  5. service+ ingress配置,供外部访问nacos web

k8s部署微服务提供端

和部署springboot项目一样。

完整代码包括docker脚本,k8s部署脚本等参见https://gitee.com/biplatform/cloud-nacos

应用配置(数据库连接等)发布到nacos配置中心。连接配置中心的参数需要写在 bootstrap.yml 里面而不能在application.yml里,服务bootstrap.yml配置如下,nacos地址用dns:

#连接配置中心的参数需要写在 bootstrap 里面,写在 application 里面无法连接配置中心,参见:https://blog.csdn.net/MrHaoo/article/details/124169653
spring:
  application:
    name: nacos-provider-demo
  cloud:
    nacos:
      discovery: #注册中心
        server-addr: 172.10.10.11:8848,172.10.10.12:8848
      config: #配置中心
        server-addr: 172.10.10.11:8848,172.10.10.12:8848
        file-extension: yml  #必须的参数,否则无法正确连接配置中心
server:
  port: 8000

如果微服务总是无法连接到nacos,注意检查nacos是否正常启动(数据库连接是否正常等),使用如下命令进入集群内nacos容器并查看日志

kubectl exec –it nacos-1 /bin/bash
tail –f logs/nacos.log –n 200

服务提供端普通pod日志查看

#获取pod名称
kubectl get pods
# -f 后跟pod名称
kubectl logs -f nacos-provider-demo-c9cd4d8c9-7chqz

注意修改k8s deploy yaml文件的Ingress name,不同服务用不同的Ingress name,下面为deploy-nacos-provider-demo.yaml的部分配置

#Ingress 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nacos-provider
  annotations:
    kubernetes.io/ingress.class: "nginx"

常见错误

  1. nacos配置中心启动报错java.nio.charset.MalformedInputException: Input length = 1

错误原因为nacos配置中心中配置或注释包含中文

删除nacos配置中心的中文部分

  1. namespace 不能用命令空间名称如prod、dev,而必须用id
  2. bootstrap.yml区分开发环境、生产环境问题

在一个bootstrap.yml文件中可同时存在两套配置

#服务配置
server:
  port: 8291
# Spring
spring:
  application:
    # 应用名称
    name: nacos-provider-demo  #应用名字
  profiles:
    # 环境配置
active: dev

##上面是基础配置,不用上配置中心那种
##下面是环境区分,主要不同环境不同文件获取
---
#开发环境
spring:
  profiles: dev
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: 0b656411-a4c8-4464-a726-d027bd0783ff
      config:
        server-addr: localhost:8848
        file-extension: yml
        group: DEFAULT_GROUP
        namespace: 0b656411-a4c8-4464-a726-d027bd0783ff
---
#正式环境
spring:
  profiles: prod
  cloud:
    nacos:
      discovery:
        server-addr: 172.10.10.11:8848,172.10.10.12:8848
        namespace: 19234622-bf8e-44f2-a82e-201b8a995131
      config:
        server-addr: 172.10.10.11:8848,172.10.10.12:8848
        file-extension: yml
        group: DEFAULT_GROUP
        namespace: 19234622-bf8e-44f2-a82e-201b8a995131

启动时指定使用的profiles即可

普通启动命令

java -jar -Dspring.profiles.active=prod provider-demo-1.0-SNAPSHOT.jar

Docker命令

ENTRYPOINT ["java", "-jar" , "-Dspring.profiles.active=prod", "/app/provider-demo-1.0-SNAPSHOT.jar"]

部署到k8s后,打开浏览器访问http://nacos-provider-demo.com:31972/tenantInfo?current=1&size=10

Demo查询的是nacos租户信息,访问效果如下:

K8s部署微服务消费端

和部署springboot项目一样。

使用openfeign实现消费端对服务端的远程调用,参见《Spring Cloud OpenFeign 详解》

Openfeign发起get请求传递对象参数,参考《OpenFeign的get方法传递对象的两种方式》

注意openfeign需要同时添加负载均衡依赖



org.springframework.cloud
spring-cloud-starter-loadbalancer

@FeignClient标明远程调用的服务名称;@GetMapping标明远程调用的服务路径;@SpringQueryMap用于传递对象参数,不加则提示MethodNotAllowed异常

@FeignClient("nacos-provider-demo")
public interface DemoFeign {
/**
* 注解传递对象 @SpringQueryMap
* @param query
* @return
*/
@GetMapping(value = "/provider/share-osci-fpar-valid/getOsciFparValids")
Result search2(@SpringQueryMap ShareOsciFparValidQO query);
}

编写一个Controller调用openfeign

@RestController
public class ConsumerController {
@Resource
private DemoFeign demoFeign;
@GetMapping("search")
public Result search(ShareOsciFparValidQO query)
{
return demoFeign.search2(query);
}
}

K8s部署网关

和部署springboot项目一样。

注意,bootstrap.yml中启用服务名称对服务的访问,否则无法通过服务名称转发请求到微服务

spring:
  cloud:
    gateway:
      discovery:
        locator:
          #开放服务名访问方式 true时候,可以使用地址 http://localhost:7000/service-wx/xler/wx/test1 就是直接可以通过服务名然后去定位controller地址进行访问
          #false就 只能 通过配置的路由进行访问
          enabled: true

在网关上部署一个静态页面

网关页面提交请求到consumer

Consumer通过openfeign请求到provider

效果如下:

至此完成个k8s集群搭建、k8s集群内部署微服务

参考文献

1. kubernetes 的安装与部署 https://www.jianshu.com/p/a4ec985977c2

2. Kubernetes进阶之路(九)Service系列之ClusterIP&NodePort https://www.jianshu.com/p/c14cce5fc7a2

3. 一关系图让你理解K8s中的概念,Pod、Service、Job等到底有啥关系 - 知乎https://zhuanlan.zhihu.com/p/105006577

4. Kubernetes(k8s)的Namespace、Pod、Label、Deployment、Service实战入门 https://blog.csdn.net/yy8623977/article/details/124769617

5. 何时使用kubernetes的deployments、pods和services?https://baijiahao.baidu.com/s?id=1690745074914054477

6. k8s部署springboot项目 https://blog.csdn.net/qq_34285557/article/details/124460872

7. k8s 新版本 部署 Ingress-nginx controller - Ingress相关概念描述 https://blog.csdn.net/qq_34285557/article/details/124254787

8. k8s 1.23版本安装Ingress-nginx - 实际参照,修改deploy.yaml含国内镜像下载 https://blog.csdn.net/weixin_43054437/article/details/127171731

9. Ingress作用 - 当我们配置了Ingress规则后,kube-proxy就不再起作用,ingress-controller会直接从service所属的endpoints中选择一个Pod,将流量直接转发到该Pod上,从而实现7层负载均衡 https://www.jianshu.com/p/23467210e62c

10. k8s ingress-nginx网络无法访问到容器问题 - 删除此配置externalTrafficPolicy: Local http://events.jianshu.io/p/4e1a97577e33

11. k8s部署Nacos集群 https://blog.csdn.net/baidu_38432732/article/details/124963395

12. [K8S系列八] K8S实战 部署spring-cloud+nacos+MySQL服务 https://www.jianshu.com/p/4b445b46eb67

13. k8s部署nacos集群(官方文档版)https://blog.csdn.net/qq_45449792/article/details/123307796

14. k8s1.23.5部署nacos持久化集群 – 配置文件名清晰、过程清晰https://blog.csdn.net/weixin_42236986/article/details/123997114

15. K8S安装部署Nacos集群 – 配置代码易复制

https://blog.csdn.net/u011936655/article/details/108364176

16. k8s安装nacos(nacos镜像版本2.0.3) – 解决新增配置失败问题,升级镜像

https://blog.csdn.net/chengqwertyuiop/article/details/125326953

17. k8s之StatefulSet详解

https://blog.csdn.net/weixin_44729138/article/details/106054025

18. SpringCloud - feign以XML格式传输

https://blog.csdn.net/baiofchao/article/details/102524933

19. Spring Cloud OpenFeign 详解

https://blog.csdn.net/qq_16116881/article/details/124267414

20. OpenFeign的get方法传递对象的两种方式

https://blog.csdn.net/qq_47493459/article/details/124290580

展开阅读全文

页面更新:2024-03-19

标签:副本   节点   集群   控制器   容器   仓库   命令   对象   名称   中心

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top