GVKun编程网logo

Dubbo 与 Kubernetes 集成(dubbo集成sentinel)

36

最近很多小伙伴都在问Dubbo与Kubernetes集成和dubbo集成sentinel这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展3、交付Dubbo微服务到kubernete

最近很多小伙伴都在问Dubbo 与 Kubernetes 集成dubbo集成sentinel这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展3、交付 Dubbo 微服务到 kubernetes 集群、docker for mac 安装 kubernetes、kubernetes dashboard、Dubbo 3.0 前瞻之对接 Kubernetes 原生服务、dubbo 服务在 kubernetes 中对外暴露服务等相关知识,下面开始了哦!

本文目录一览:

Dubbo 与 Kubernetes 集成(dubbo集成sentinel)

Dubbo 与 Kubernetes 集成(dubbo集成sentinel)

Dubbo 应用迁移到 docker 的问题

Dubbo 是阿里开源的一套服务治理与 rpc 框架,服务的提供者通过 zookeeper 把自己的服务发布上去,然后服务调用方通过 zk 获取服务的 ip 和端口,dubbo 客户端通过自己的软负载功能自动选择服务提供者并调用,整个过程牵涉到的三方关系如下图所示。

在正常的情况下,这三方都在同一个互通的网段,provider 提供给 zk 的就是获取到的本机地址,consumer 能访问到这个地址。

但是假如服务放在 docker 容器中,而调用者并不在 docker 中,它们的网段是不一样的。

这个时候就出现问题了,consumer 无法访问到 provider 了。

Dubbo 提供的解决方案

新版的 Dubbo 提供了四个配置来指定与注册服务相关的地址和端口。

DUBBO_IP_TO_REGISTRY: 要发布到注册中心上的地址
DUBBO_PORT_TO_REGISTRY: 要发布到注册中心上的端口
DUBBO_IP_TO_BIND: 要绑定的服务地址(监听的地址)
DUBBO_PORT_TO_BIND: 要绑定的服务端口

以 IP 地址为例,Dubbo 先找是不是有 DUBBO_IP_TO_BIND 这个配置,如果有使用配置的地址,如果没有就取本机地址。然后继续找 DUBBO_IP_TO_REGISTRY,如果有了配置,使用配置,否则就使用 DUBBO_IP_TO_BIND。具体代码如下:

        /**
         * Register & bind IP address for service provider, can be configured separately.
         * Configuration priority: environment variables -> java system properties -> host property in config file ->
         * /etc/hosts -> default network address -> first available network address
         *
         * @param protocolConfig
         * @param registryURLs
         * @param map
         * @return
         */
        private static String findConfigedHosts(ServiceConfig<?> sc,
                                                ProtocolConfig protocolConfig,
                                                List<URL> registryURLs,
                                                Map<String, String> map) {
            boolean anyhost = false;

            String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
            if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
                throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
            }

            // if bind ip is not found in environment, keep looking up
            if (StringUtils.isEmpty(hostToBind)) {
                hostToBind = protocolConfig.getHost();
                if (sc.getProvider() != null && StringUtils.isEmpty(hostToBind)) {
                    hostToBind = sc.getProvider().getHost();
                }
                if (isInvalidLocalHost(hostToBind)) {
                    anyhost = true;
                    try {
                        logger.info("No valid ip found from environment, try to find valid host from DNS.");
                        hostToBind = InetAddress.getLocalHost().getHostAddress();
                    } catch (UnknownHostException e) {
                        logger.warn(e.getMessage(), e);
                    }
                    if (isInvalidLocalHost(hostToBind)) {
                        if (CollectionUtils.isNotEmpty(registryURLs)) {
                            for (URL registryURL : registryURLs) {
                                if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
                                    // skip multicast registry since we cannot connect to it via Socket
                                    continue;
                                }
                                try (Socket socket = new Socket()) {
                                    SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                                    socket.connect(addr, 1000);
                                    hostToBind = socket.getLocalAddress().getHostAddress();
                                    break;
                                } catch (Exception e) {
                                    logger.warn(e.getMessage(), e);
                                }
                            }
                        }
                        if (isInvalidLocalHost(hostToBind)) {
                            hostToBind = getLocalHost();
                        }
                    }
                }
            }

            map.put(BIND_IP_KEY, hostToBind);

            // registry ip is not used for bind ip by default
            String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
            if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
                throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
            } else if (StringUtils.isEmpty(hostToRegistry)) {
                // bind ip is used as registry ip by default
                hostToRegistry = hostToBind;
            }

            map.put(ANYHOST_KEY, String.valueOf(anyhost));

            return hostToRegistry;
        }

然后我们看这个 getValueFromConfig (),它调用了下面的函数,可以看到,它是先找环境变量,再找 properties。

    public static String getSystemProperty(String key) {
        String value = System.getenv(key);
        if (StringUtils.isEmpty(value)) {
            value = System.getProperty(key);
        }
        return value;
    }

所以我们通过环境变量,就能修改 Dubbo 发布到 zookeeper 上的地址和端口。假如我们通过 docker 镜像启动了一个 dubbo provider,并且它的服务端口是 8888,假设主机地址为 192.168.1.10,那么我们通过下面的命令,

docker run -e DUBBO_IP_TO_REGISTRY=192.168.1.10 -e DUBBO_PORT_TO_REGISTRY=8888 -p 8888:8888 dubbo_image

就能让内部的服务以 192.168.1.10:8888 的地址发布。

我们通过官方的实例来演示一下,因为官方提供的案例都很久了,所以我自己重新搞了一个示例,代码在 https://github.com/XinliNiu/dubbo-docker-sample.git 。

先启动一个 zookeeper,暴露 2181 端口。

docker run --name zkserver --rm -p 2181:2181  -d zookeeper:3.4.9

看一下 zk 起来了

niuxinli@niuxinli-B450M-DS3H:~/dubbo-samples-docker$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
5efc1f17fba0        zookeeper:3.4.9     "/docker-entrypoint.…"   4 seconds ago       Up 2 seconds        2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp   zkserver

把代码导入 IDE,修改 dubbo-docker-provide.xml,把地址改成刚发布到 zk 的地址和端口,我的地址是 192.168.1.8。

运行 DubboApplication,这时候可以看到在 zk 上注册了服务。

修改 dubbo-docker-consumer.xml 里的 zk 地址,执行单元测试,能正常访问。

把 DubboApplication 导出成可以执行的 jar 包,名字叫 app.jar,创建如下 Dockerfile

FROM openjdk:8-jdk-alpine
ADD app.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -jar /app.jar

创建 dubbo-demo 镜像,在同样的目录里执行 docker build。

docker build --no-cache -t dubbo-demo .

正常启动镜像

docker run  -p 20880:20880  -it --rm dubbo-demo

发现是 172.16.0.3 的地址,这个是访问不了的。

传入环境变量重新启动,

docker run  -e DUBBO_IP_TO_REGISTRY=192.168.1.8 -e DUBBO_PORT_TO_REGISTRY=20880 -p 20880:20880  -it --rm dubbo-demo

这时候就变成主机地址了。

docker run --name zkserver --rm -p 42181:2181  -d zookeeper:3.4.9

看一下 zk 起来了

niuxinli@niuxinli-B450M-DS3H:~/docker_dubbo_demo/dubbo-samples/dubbo-samples-docker$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
5efc1f17fba0        zookeeper:3.4.9     "/docker-entrypoint.…"   4 seconds ago       Up 2 seconds        2888/tcp, 3888/tcp, 0.0.0.0:42181->2181/tcp   zkserver

现在启动 dubbo provider,使用 link 的方式连接 zk,我的本机地址是 192.168.1.8,provider 自己暴露的端口为 20880,主机暴露端口改成 28888。

在 Kubernetes 中使用 Dubbo

当在 Kubernetes 中启动多个副本的时候,指定具体的 IP 和具体的端口,都是不可行的,因为每个机器的 IP 都不一样,不能写很多个 yaml 文件,而且一旦指定了具体端口,那这台主机的这个端口就被占用了。

我们可以通过创建 Service,使用 NodePort 的方式,把端口固定住,这样端口的问题就解决了。因为是对外服务,所以使用 ClusterIP 肯定是不行了,IP 有两种解决办法:

(1) 使用 Kubernetes 的 downward api 动态的传入主机的 ip。

(2) 传固定的 loadbalancer 的地址,例如在所有的 node 之外有一个 F5。

不管哪种方法,都是一种妥协的办法,很不 “云原生”,我演示一下使用 downward api 动态传入主机地址,并使用 nodeport 固定端口的方式。

我的 kubernetes 集群如下:

角色 地址
master 192.168.174.50
node1 192.168.174.51
node2 192.168.174.52
node3 192.168.174.53

zk 的地址是 192.168.1.8,它与集群的主机互通。

我没有建 private 镜像仓库,把我之前打好的 dubbo-demo 直接 push 到 docker-hub 上了,名字是 nxlhero/dubbo-demo。

创建 Service,使用的 NodePort 为 30001,创建 4 个副本,这样 3 台机器上正好有一台起两个 pod。

apiVersion: v1
kind: Service
metadata:
  name: dubbo-docker
  labels:
    run: dubbo
spec:
  type: NodePort
  ports:
  - port: 20880
    targetPort: 20880
    nodePort: 30001
  selector:
    run: dubbo-docker
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dubbo-docker
spec:
  selector:
    matchLabels:
      run: dubbo
  replicas: 4
  template:
    metadata:
      labels:
        run: dubbo
    spec:
      containers:
      - name: dubbo-docker
        image: nxlhero/dubbo-demo
        env:
        - name: DUBBO_IP_TO_REGISTRY
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: DUBBO_PORT_TO_REGISTRY
          value: "30001"
        tty: true
        ports:
        - containerPort: 20880

这个 yaml 最关键的地方就是环境变量,主机 IP 通过 downward apid 传入,端口使用固定的 nodeport。

        env:
        - name: DUBBO_IP_TO_REGISTRY
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: DUBBO_PORT_TO_REGISTRY
          value: "30001"

创建 Service,启动后可以看到 zookeeper 上的地址都是主机的地址和 nodeport。

原文出处:https://www.cnblogs.com/nxlhero/p/11789006.html

3、交付 Dubbo 微服务到 kubernetes 集群

3、交付 Dubbo 微服务到 kubernetes 集群

1. 基础架构

1.1. 架构图

  • Zookeeper 是 Dubbo 微服务集群的注册中心
  • 它的高可用机制和 k8s 的 etcd 集群一致
  • java 编写,需要 jdk 环境

1.2. 节点规划

主机名 角色 ip
hdss7-11.host.com k8s 代理节点 1,zk1 10.4.7.11
hdss7-12.host.com k8s 代理节点 2,zk2 10.4.7.12
hdss7-21.host.com k8s 运算节点 1,zk3 10.4.7.21
hdss7-22.host.com k8s 运算节点 2,jenkins 10.4.7.22
hdss7-200.host.com k8s 运维节点(docker 仓库) 10.4.7.200

2. 部署 zookeeper

2.1. 安装 jdk 1.8(3 台 zk 节点都要安装)

//解压、创建软链接
[root@hdss7-11 src]# mkdir /usr/java
[root@hdss7-11 src]# tar xf jdk-8u221-linux-x64.tar.gz  -C /usr/java/
[root@hdss7-11 src]# ln -s /usr/java/jdk1.8.0_221/ /usr/java/jdk
[root@hdss7-11 src]# cd /usr/java/
[root@hdss7-11 java]# ll
total 0
lrwxrwxrwx 1 root root  23 Nov 30 17:38 jdk -> /usr/java/jdk1.8.0_221/
drwxr-xr-x 7   10  143 245 Jul  4 19:37 jdk1.8.0_221

//创建环境变量
[root@hdss7-11 java]# vi /etc/profile
export JAVA_HOME=/usr/java/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/bin:$PATH
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar

//source并检查
[root@hdss7-11 java]# source /etc/profile
[root@hdss7-11 java]# java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

2.2. 安装 zk(3 台节点都要安装)

zookeeper 官方地址

2.2.1. 解压,创建软链接

[root@hdss7-11 src]# tar xf zookeeper-3.4.14.tar.gz  -C /opt/
[root@hdss7-11 src]# ln -s /opt/zookeeper-3.4.14/ /opt/zookeeper

2.2.2. 创建数据目录和日志目录

[root@hdss7-11 opt]# mkdir  -pv /data/zookeeper/data /data/zookeeper/logs
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/zookeeper’
mkdir: created directory ‘/data/zookeeper/data’
mkdir: created directory ‘/data/zookeeper/logs’

2.2.3. 配置

//各节点相同
[root@hdss7-11 opt]# vi /opt/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/logs
clientPort=2181
server.1=zk1.od.com:2888:3888
server.2=zk2.od.com:2888:3888
server.3=zk3.od.com:2888:3888

myid

//各节点不同
[root@hdss7-11 opt]# vi /data/zookeeper/data/myidvi
1
[root@hdss7-12 opt]# vi /data/zookeeper/data/myid
2
[root@hdss7-21 opt]# vi /data/zookeeper/data/myid
3

2.2.4. 做 dns 解析

[root@hdss7-11 opt]# vi /var/named/od.com.zone

$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2019111006 ; serial                        //序列号前滚1
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
harbor             A    10.4.7.200
k8s-yaml           A    10.4.7.200
traefik            A    10.4.7.10
dashboard          A    10.4.7.10
zk1                A    10.4.7.11
zk2                A    10.4.7.12
zk3                A    10.4.7.21

[root@hdss7-11 opt]# systemctl restart named
[root@hdss7-11 opt]# dig -t A zk1.od.com @10.4.7.11 +short
10.4.7.11

2.2.4. 依次启动并检查

启动

[root@hdss7-11 opt]# /opt/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@hdss7-12 opt]# /opt/zookeeper/bin/zkServer.sh start

[root@hdss7-21 opt]# /opt/zookeeper/bin/zkServer.sh start

检查

[root@hdss7-11 opt]# netstat -ntlup|grep 2181
tcp6       0      0 :::2181                 :::*                    LISTEN      69157/java   

[root@hdss7-11 opt]# zookeeper/bin/zkServer.sh  status  
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower

[root@hdss7-12 opt]# zookeeper/bin/zkServer.sh  status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: leader

3. 部署 jenkins

jenkins 官网 jenkins 镜像

3.1. 准备镜像

hdss7-200 上

[root@hdss7-200 ~]# docker pull jenkins/jenkins:2.190.3
[root@hdss7-200 ~]# docker images |grep jenkins
[root@hdss7-200 ~]# docker tag 22b8b9a84dbe harbor.od.com/public/jenkins:v2.190.3
[root@hdss7-200 ~]# docker push  harbor.od.com/public/jenkins:v2.190.3

3.2. 制作自定义镜像

3.2.1. 生成 ssh 秘钥对

[root@hdss7-200 ~]# ssh-keygen -t rsa -b 2048 -C "8614610@qq.com" -N "" -f /root/.ssh/id_rsa
  • 此处用自己的邮箱

3.2.2. 准备 get-docker.sh 文件

[root@hdss7-200 ~]#  curl -fsSL get.docker.com -o get-docker.sh
[root@hdss7-200 ~]# chmod +x  get-docker.sh

3.2.3. 准备 config.json 文件

cp /root/.docker/config.json  .
cat  /root/.docker/config.json
{
	"auths": {
		"harbor.od.com": {
			"auth": "YWRtaW46SGFyYm9yMTIzNDU="
		}
	},
	"HttpHeaders": {
		"User-Agent": "Docker-Client/19.03.4 (linux)"
	}

3.2.4. 创建目录并准备 Dockerfile

[root@hdss7-200 ~]# mkdir /data/dockerfile/jenkins -p
[root@hdss7-200 ~]# cd /data/dockerfile/jenkins/

[root@hdss7-200 jenkins]# vi Dockerfile
FROM harbor.od.com/public/jenkins:v2.190.3
USER root
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\ 
    echo ''Asia/Shanghai'' >/etc/timezone
ADD id_rsa /root/.ssh/id_rsa
ADD config.json /root/.docker/config.json
ADD get-docker.sh /get-docker.sh
RUN echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config &&\
    /get-docker.sh
  • 设置容器用户为 root
  • 设置容器内的时区
  • 将创建的 ssh 私钥加入(使用 git 拉代码是要用,配对的公钥配置在 gitlab 中)
  • 加入了登陆自建 harbor 仓库的 config 文件
  • 修改了 ssh 客户端的配置,不做指纹验证
  • 安装一个 docker 的客户端 //build 如果失败,在 get-docker.sh 后加 --mirror=Aliyun

3.3. 制作自定义镜像

//准备所需文件,拷贝至/data/dockerfile/jenkins
[root@hdss7-200 jenkins]# pwd
/data/dockerfile/jenkins
[root@hdss7-200 jenkins]# ll
total 32
-rw------- 1 root root   151 Nov 30 18:35 config.json
-rw-r--r-- 1 root root   349 Nov 30 18:31 Dockerfile
-rwxr-xr-x 1 root root 13216 Nov 30 18:31 get-docker.sh
-rw------- 1 root root  1675 Nov 30 18:35 id_rsa

//执行build
 docker build . -t harbor.od.com/infra/jenkins:v2.190.3 

//公钥上传到gitee测试此镜像是否可以成功连接
[root@hdss7-200 harbor]# docker run --rm harbor.od.com/infra/jenkins:v2.190.3 ssh -i /root/.ssh/id_rsa -T git@gitee.com
Warning: Permanently added ''gitee.com,212.64.62.174'' (ECDSA) to the list of known hosts.
Hi StanleyWang (DeployKey)! You''ve successfully authenticated, but GITEE.COM does not provide shell access.
Note: Perhaps the current use is DeployKey.
Note: DeployKey only supports pull/fetch operations

3.4. 创建 infra 仓库

3.5. 创建 kubernetes 名称空间并在此创建 secret

[root@hdss7-21 ~]# kubectl create namespace infra
[root@hdss7-21 ~]# kubectl create secret docker-registry harbor --docker-server=harbor.od.com --docker-username=admin --docker-password=Harbor12345 -n infra

3.6. 推送镜像

[root@hdss7-200 jenkins]# docker push harbor.od.com/infra/jenkins:v2.190.3

3.7. 准备共享存储

运维主机 hdss7-200 和所有运算节点上,这里指 hdss7-21、22

3.7.1. 安装 nfs-utils -y

[root@hdss7-200 jenkins]# yum install nfs-utils -y

3.7.2. 配置 NFS 服务

运维主机 hdss7-200 上

[root@hdss7-200 jenkins]# vi /etc/exports
/data/nfs-volume 10.4.7.0/24(rw,no_root_squash)

3.7.3. 启动 NFS 服务

运维主机 hdss7-200 上

[root@hdss7-200 ~]# mkdir -p /data/nfs-volume
[root@hdss7-200 ~]# systemctl start nfs
[root@hdss7-200 ~]# systemctl enable nfs

3.8. 准备资源配置清单

运维主机 hdss7-200 上

[root@hdss7-200 ~]# cd /data/k8s-yaml/
[root@hdss7-200 k8s-yaml]# mkdir /data/k8s-yaml/jenkins && mkdir /data/nfs-volume/jenkins_home && cd  jenkins

dp.yaml

[root@hdss7-200 jenkins]# vi dp.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: jenkins
  namespace: infra
  labels: 
    name: jenkins
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: jenkins
  template:
    metadata:
      labels: 
        app: jenkins 
        name: jenkins
    spec:
      volumes:
      - name: data
        nfs: 
          server: hdss7-200
          path: /data/nfs-volume/jenkins_home
      - name: docker
        hostPath: 
          path: /run/docker.sock
          type: ''''
      containers:
      - name: jenkins
        image: harbor.od.com/infra/jenkins:v2.190.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
        env:
        - name: JAVA_OPTS
          value: -Xmx512m -Xms512m
        volumeMounts:
        - name: data
          mountPath: /var/jenkins_home
        - name: docker
          mountPath: /run/docker.sock
      imagePullSecrets:
      - name: harbor
      securityContext: 
        runAsUser: 0
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

svc.yaml

[root@hdss7-200 jenkins]# vi dp.yaml
kind: Service
apiVersion: v1
metadata: 
  name: jenkins
  namespace: infra
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  selector:
    app: jenkins

ingress.yaml

kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: jenkins
  namespace: infra
spec:
  rules:
  - host: jenkins.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: jenkins
          servicePort: 80

3.9. 应用资源配置清单

任意运算节点上

[root@hdss7-21 etcd]# kubectl apply -f http://k8s-yaml.od.com/jenkins/dp.yaml
[root@hdss7-21 etcd]# kubectl apply -f http://k8s-yaml.od.com/jenkins/svc.yaml
[root@hdss7-21 etcd]# kubectl apply -f http://k8s-yaml.od.com/jenkins/ingress.yaml

[root@hdss7-21 etcd]# kubectl get pods -n infra
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-54b8469cf9-v46cc   1/1     Running   0          168m
[root@hdss7-21 etcd]# kubectl get all  -n infra
NAME                           READY   STATUS    RESTARTS   AGE
pod/jenkins-54b8469cf9-v46cc   1/1     Running   0          169m


NAME              TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
service/jenkins   ClusterIP   192.168.183.210   <none>        80/TCP    2d21h


NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/jenkins   1/1     1            1           2d21h

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/jenkins-54b8469cf9   1         1         1       2d18h
replicaset.apps/jenkins-6b6d76f456   0         0         0       2d21h

3.10. 解析域名

hdss7-11 上

[root@hdss7-11 ~]# vi /var/named/od.com.zone
$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2019111007 ; serial
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
...
...
jenkins            A    10.4.7.10

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A jenkins.od.com @10.4.7.11 +short
10.4.7.10

3.11. 浏览器访问

访问:http://jenkins.od.com 需要输入初始密码:

初始密码查看(也可在 log 里查看):

[root@hdss7-200 jenkins]# cat /data/nfs-volume/jenkins_home/secrets/initialAdminPassword

3.12. 页面配置 jenkins

3.12.1. 配置用户名密码

用户名:admin 密码:admin123 // 后续依赖此密码,请务必设置此密码

3.12.2. 设置 configure global security

允许匿名用户访问

阻止跨域请求,勾去掉

3.12.3. 安装好流水线插件 Blue-Ocean

注意安装插件慢的话可以设置清华大学加速 hdss-200 上

cd /data/nfs-volume/jenkins_home/updates
sed -i ''s/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g'' default.json && sed -i ''s/http:\/\/www.google.com/https:\/\/www.baidu.com/g'' default.json

4. 最后的准备工作

4.1. 检查 jenkins 容器里的 docker 客户端

验证当前用户,时区 ,sock 文件是否可用

验证 kubernetes 名称空间创建的 secret 是否可登陆到 harbor 仓库

4.2. 检查 jenkins 容器里的 SSH key

验证私钥,是否能登陆到 gitee 拉代码

4.3. 部署 maven 软件

编译 java,早些年用 javac-->ant -->maven-->Gragle 在运维主机 hdss7-200 上二进制部署,这里部署 maven-3.6.2 版本 mvn 命令是一个脚本,如果用 jdk7,可以在脚本里修改

4.3.1. 下载安装包

maven 官方下载地址

4.3.2. 创建目录并解压

目录 8u232 是根据 docker 容器里的 jenkins 的 jdk 版本命名,请严格按照此命名

[root@hdss7-200 src]# mkdir /data/nfs-volume/jenkins_home/maven-3.6.1-8u232
[root@hdss7-200 src]# tar xf apache-maven-3.6.1-bin.tar.gz  -C /data/nfs-volume/jenkins_home/maven-3.6.1-8u232
[root@hdss7-200 src]# cd /data/nfs-volume/jenkins_home/maven-3.6.1-8u232
[root@hdss7-200 maven-3.6.1-8u232]# ls
apache-maven-3.6.1
[root@hdss7-200 maven-3.6.1-8u232]# mv apache-maven-3.6.1/ ../ && mv ../apache-maven-3.6.1/* .
[root@hdss7-200 maven-3.6.1-8u232]# ll
total 28
drwxr-xr-x 2 root root     97 Dec  3 19:04 bin
drwxr-xr-x 2 root root     42 Dec  3 19:04 boot
drwxr-xr-x 3  501 games    63 Apr  5  2019 conf
drwxr-xr-x 4  501 games  4096 Dec  3 19:04 lib
-rw-r--r-- 1  501 games 13437 Apr  5  2019 LICENSE
-rw-r--r-- 1  501 games   182 Apr  5  2019 NOTICE
-rw-r--r-- 1  501 games  2533 Apr  5  2019 README.txt

4.3.3. 设置 settings.xml 国内镜像源

搜索替换:
[root@hdss7-200 maven-3.6.1-8u232]# vi /data/nfs-volume/jenkins_home/maven-3.6.1-8u232/conf/settings.xml
<mirror>
  <id>nexus-aliyun</id>
  <mirrorOf>*</mirrorOf>
  <name>Nexus aliyun</name>
  <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

4.3. 制作 dubbo 微服务的底包镜像

运维主机 hdss7-200 上

4.3.1. 自定义 Dockerfile

root@hdss7-200 dockerfile]# mkdir jre8
[root@hdss7-200 dockerfile]# cd jre8/
[root@hdss7-200 jre8]# pwd
/data/dockerfile/jre8

[root@hdss7-200 jre8]# vi Dockfile
FROM harbor.od.com/public/jre:8u112
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&\
    echo ''Asia/Shanghai'' >/etc/timezone
ADD config.yml /opt/prom/config.yml
ADD jmx_javaagent-0.3.1.jar /opt/prom/
WORKDIR /opt/project_dir
ADD entrypoint.sh /entrypoint.sh
CMD ["/entrypoint.sh"]
  • 普罗米修斯的监控匹配规则
  • java agent 收集 jvm 的信息,采集 jvm 的 jar 包
  • docker 运行的默认启动脚本 entrypoint.sh

4.3.2. 准备 jre 底包(7 版本有一个 7u80)

[root@hdss7-200 jre8]# docker pull docker.io/stanleyws/jre8:8u112
[root@hdss7-200 jre8]# docker images |grep jre
stanleyws/jre8                     8u112                      fa3a085d6ef1        2 years ago         363MB
[root@hdss7-200 jre8]# docker tag fa3a085d6ef1 harbor.od.com/public/jre:8u112
[root@hdss7-200 jre8]# docker push  harbor.od.com/public/jre:8u112

4.3.3. 准备 java-agent 的 jar 包

[root@hdss7-200 jre8]# wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar -O jmx_javaagent-0.3.1.jar

4.3.3. 准备 config.yml 和 entrypoint.sh

[root@hdss7-200 jre8]# vi config.yml
---
rules:
  - pattern: ''.*''

[root@hdss7-200 jre8]# vi entrypoint.sh
#!/bin/sh
M_OPTS="-Duser.timezone=Asia/Shanghai -javaagent:/opt/prom/jmx_javaagent-0.3.1.jar=$(hostname -i):${M_PORT:-"12346"}:/opt/prom/config.yml"
C_OPTS=${C_OPTS}
JAR_BALL=${JAR_BALL}
exec java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL}

[root@hdss7-200 jre8]# chmod +x entrypoint.sh 
  

4.3.4.harbor 创建 base 项目

4.3.5. 构建 dubbo 微服务的底包并推到 harbor 仓库

[root@hdss7-200 jre8]# docker build . -t harbor.od.com/base/jre8:8u112

[root@hdss7-200 jre8]# docker push  harbor.od.com/base/jre8:8u112

5. 交付 dubbo 微服务至 kubenetes 集群

5.1. 配置 New job 流水线

添加构建参数: // 以下配置项是王导根据多年生产经验总结出来的 -- 运维甩锅大法(姿势要帅,动作要快)

登陆 jenkins-----> 选择 NEW-ITEM----->item name :dubbo-demo----->Pipeline------>ok

需要保留多少此老的构建,这里设置,保留三天,30 个

点击:“This project is parameterized” 使用参数化构建 jenkins

添加参数 String Parameter:8 个 ------Trim the string 都勾选 app_name

image_name

git_repo

git_ver

add_tag

mvn_dir

target_dir

mvn_cmd

添加 Choice Parameter:2 个 base_image

maven

5.2..Pipeline Script

pipeline {
  agent any 
    stages {
      stage(''pull'') { //get project code from repo 
        steps {
          sh "git clone ${params.git_repo} ${params.app_name}/${env.BUILD_NUMBER} && cd ${params.app_name}/${env.BUILD_NUMBER} && git checkout ${params.git_ver}"
        }
      }
      stage(''build'') { //exec mvn cmd
        steps {
          sh "cd ${params.app_name}/${env.BUILD_NUMBER}  && /var/jenkins_home/maven-${params.maven}/bin/${params.mvn_cmd}"
        }
      }
      stage(''package'') { //move jar file into project_dir
        steps {
          sh "cd ${params.app_name}/${env.BUILD_NUMBER} && cd ${params.target_dir} && mkdir project_dir && mv *.jar ./project_dir"
        }
      }
      stage(''image'') { //build image and push to registry
        steps {
          writeFile file: "${params.app_name}/${env.BUILD_NUMBER}/Dockerfile", text: """FROM harbor.od.com/${params.base_image}
ADD ${params.target_dir}/project_dir /opt/project_dir"""
          sh "cd  ${params.app_name}/${env.BUILD_NUMBER} && docker build -t harbor.od.com/${params.image_name}:${params.git_ver}_${params.add_tag} . && docker push harbor.od.com/${params.image_name}:${params.git_ver}_${params.add_tag}"
        }
      }
    }
}

5.3.harbor 创建 app 项目,把 dubbo 服务镜像管理起来

5.4. 创建 app 名称空间,并添加 secret 资源

任意运算节点上 因为要去拉 app 私有仓库的镜像,所以添加 secret 资源

[root@hdss7-21 bin]# kubectl create ns app
namespace/app created
[root@hdss7-21 bin]# kubectl create secret docker-registry harbor --docker-server=harbor.od.com --docker-username=admin --docker-password=Harbor12345 -n app
secret/harbor created

5.5. 交付 dubbo-demo-service

5.5.1.jenkins 传参,构建 dubbo-demo-service 镜像,传到 harbor

5.5.2. 创建 dubbo-demo-service 的资源配置清单

特别注意:dp.yaml 的 image 替换成自己打包的镜像名称 hdss7-200 上

[root@hdss7-200 dubbo-demo-service]# vi dp.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-demo-service
  namespace: app
  labels: 
    name: dubbo-demo-service
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-demo-service
  template:
    metadata:
      labels: 
        app: dubbo-demo-service
        name: dubbo-demo-service
    spec:
      containers:
      - name: dubbo-demo-service
        image: harbor.od.com/app/dubbo-demo-service:master_191201_1200
        ports:
        - containerPort: 20880
          protocol: TCP
        env:
        - name: JAR_BALL
          value: dubbo-server.jar
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

5.5.3. 应用 dubbo-demo-service 资源配置清单

任意运算节点上

[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-service/dp.yaml
deployment.extensions/dubbo-demo-service created

5.5.4. 检查启动状态

dashboard 查看日志

zk 注册中心查看

5.6. 交付 dubbo-Monitor

dubbo-monitor 实际上就是从注册中心 registry 去数据出来然后展示的工具 两个开源软件:1、dubbo-admin 2、dubbo-monitor。此处我们用 dubbo-minitor

5.6.1. 准备 docker 镜像

5.6.1.1. 下载源码包、解压
[root@hdss7-200 src]# ll|grep dubbo
-rw-r--r-- 1 root root  23468109 Dec  4 11:50 dubbo-monitor-master.zip
[root@hdss7-200 src]# unzip  dubbo-monitor-master.zip 
[root@hdss7-200 src]# ll|grep dubbo
drwxr-xr-x 3 root root        69 Jul 27  2016 dubbo-monitor-master
-rw-r--r-- 1 root root  23468109 Dec  4 11:50 dubbo-monitor-master.zip
5.6.1.2. 修改以下项配置
[root@hdss7-200 conf]# pwd
/opt/src/dubbo-monitor-master/dubbo-monitor-simple/conf

[root@hdss7-200 conf]# vi dubbo_origin.properties 
dubbo.registry.address=zookeeper://zk1.od.com:2181?backup=zk2.od.com:2181,zk3.od.com:2181
dubbo.protocol.port=20880
dubbo.jetty.port=8080
dubbo.jetty.directory=/dubbo-monitor-simple/monitor
dubbo.statistics.directory=/dubbo-monitor-simple/statistics
dubbo.charts.directory=/dubbo-monitor-simple/charts
dubbo.log4j.file=logs/dubbo-monitor.log
5.6.1.3. 制作镜像
5.6.1.3.1. 准备环境
  • 由于是虚拟机环境,这里 java 给的内存太大,需要给小一些,nohup 替换成 exec,要在前台跑,去掉结尾 & 符,删除 nohup 行下所有行
[root@hdss7-200 bin]# vi /opt/src/dubbo-monitor-master/dubbo-monitor-simple/bin/start.sh 
    JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
    JAVA_MEM_OPTS=" -server -Xms1g -Xmx1g -XX:PermSize=128m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi

echo -e "Starting the $SERVER_NAME ...\c"
nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS -classpath $CONF_DIR:$LIB_JARS com.alibaba.dubbo.container.Main > $STDOUT_FILE 2>&1 &
  • sed 命令替换,用到了 sed 模式空间
sed -r -i -e ''/^nohup/{p;:a;N;$!ba;d}''  ./dubbo-monitor-simple/bin/start.sh && sed  -r -i -e "s%^nohup(.*)%exec \1%"  /opt/src/dubbo-monitor-master/dubbo-monitor-simple/bin/start.sh 

// 调小内存,然后 nohup 行结尾的 & 去掉!!!

  • 为了规范,复制到 data 下
[root@hdss7-200 src]# mv dubbo-monitor-master dubbo-monitor
[root@hdss7-200 src]# cp -a dubbo-monitor /data/dockerfile/
[root@hdss7-200 src]# cd /data/dockerfile/dubbo-monitor/
5.6.1.3.2. 准备 Dockerfile
[root@hdss7-200 dubbo-monitor]# pwd
/data/dockerfile/dubbo-monitor

[root@hdss7-200 dubbo-monitor]# cat Dockerfile 
FROM jeromefromcn/docker-alpine-java-bash
MAINTAINER Jerome Jiang
COPY dubbo-monitor-simple/ /dubbo-monitor-simple/
CMD /dubbo-monitor-simple/bin/start.sh
5.6.1.3.3.build 镜像并 push 到 harbor 仓库
[root@hdss7-200 dubbo-monitor]# docker build . -t harbor.od.com/infra/dubbo-monitor:latest
[root@hdss7-200 dubbo-monitor]# docker push harbor.od.com/infra/dubbo-monitor:latest

5.6.2. 解析域名

[root@hdss7-11 ~]# vi /var/named/od.com.zone 
$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2019111008 ; serial
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
  。。。略                              
dubbo-monitor      A    10.4.7.10

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A dubbo-monitor.od.com @10.4.7.11 +short
10.4.7.10

5.6.3. 准备 k8s 资源配置清单

  • dp.yaml
[root@hdss7-200 k8s-yaml]# pwd
/data/k8s-yaml
[root@hdss7-200 k8s-yaml]# pwd
/data/k8s-yaml
[root@hdss7-200 k8s-yaml]# mkdir dubbo-monitor
[root@hdss7-200 k8s-yaml]# cd dubbo-monitor/
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-monitor
  namespace: infra
  labels: 
    name: dubbo-monitor
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-monitor
  template:
    metadata:
      labels: 
        app: dubbo-monitor
        name: dubbo-monitor
    spec:
      containers:
      - name: dubbo-monitor
        image: harbor.od.com/infra/dubbo-monitor:latest
        ports:
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880
          protocol: TCP
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600
  • svc.yaml
kind: Service
apiVersion: v1
metadata: 
  name: dubbo-monitor
  namespace: infra
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector: 
    app: dubbo-monitor
  • ingress.yaml
kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: dubbo-monitor
  namespace: infra
spec:
  rules:
  - host: dubbo-monitor.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: dubbo-monitor
          servicePort: 8080

5.6.4. 应用资源配置清单

[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/dp.yaml
deployment.extensions/dubbo-monitor created
[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/svc.yaml
service/dubbo-monitor created
[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/ingress.yaml
ingress.extensions/dubbo-monitor created

5.6.5. 浏览器访问

5.7. 交付 dubbo-demo-consumer

5.7.1.jenkins 传参,构建 dubbo-demo-service 镜像,传到 harbor

jenkins 的 jar 包本地缓存

5.7.2. 创建 dubbo-demo-consumer 的资源配置清单

运维主机 hdss7-200 上 特别注意:dp.yaml 的 image 替换成自己打包的镜像名称 dp.yaml

[root@hdss7-200 k8s-yaml]# pwd
/data/k8s-yaml
[root@hdss7-200 k8s-yaml]# mkdir dubbo-demo-consumer
[root@hdss7-200 k8s-yaml]# cd dubbo-demo-consumer/
[root@hdss7-200 k8s-yaml]# vi dp.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-demo-consumer
  namespace: app
  labels: 
    name: dubbo-demo-consumer
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-demo-consumer
  template:
    metadata:
      labels: 
        app: dubbo-demo-consumer
        name: dubbo-demo-consumer
    spec:
      containers:
      - name: dubbo-demo-consumer
        image: harbor.od.com/app/dubbo-demo-consumer:master_191204_1307
        ports:
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880
          protocol: TCP
        env:
        - name: JAR_BALL
          value: dubbo-client.jar
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

svc.yaml

kind: Service
apiVersion: v1
metadata: 
  name: dubbo-demo-consumer
  namespace: app
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector: 
    app: dubbo-demo-consumer

ingress.yaml

kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: dubbo-demo-consumer
  namespace: app
spec:
  rules:
  - host: demo.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: dubbo-demo-consumer
          servicePort: 8080

5.7.3. 应用 dubbo-demo-consumer 资源配置清单

任意运算节点上

[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/dp.yaml
deployment.extensions/dubbo-demo-consumer created
[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/svc.yaml
service/dubbo-demo-consumer created
[root@hdss7-21 bin]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/ingress.yaml
ingress.extensions/dubbo-demo-consumer created

5.7.4. 解析域名

hdss7-11 上

[root@hdss7-11 ~]# vi /var/named/od.com.zone 
$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2019111009 ; serial                      
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
...
...
demo               A    10.4.7.10

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A demo.od.com @10.4.7.11 +short 
10.4.7.10

5.7.5. 检查启动状态

  • dashboard 查看: http://dashboard.od.com

  • dubbo-monitor 查看: http://dubbo-monitor.od.com

  • 访问 demo.od.com 查看: http://demo.od.com/hello?name=wang

6. 实战维护 dubbo 微服务集群

6.1. 更新(rolling update)

  • 修改代码提交 GIT(发版)
  • 使用 jenkins 进行 CI(持续构建)
  • 修改并应用 k8s 资源配置清单
  • 或者在 k8s 上修改 yaml 的 harbor 镜像地址

6.2. 扩容(scaling)

  • 在 k8s 的 dashboard 上直接操作:登陆 dashboard 页面 --> 部署 --> 伸缩 --> 修改数量 --> 确定
  • 命令行扩容,如下示例:
* Examples:
  # Scale a replicaset named ''foo'' to 3.
  kubectl scale --replicas=3 rs/foo
  
  # Scale a resource identified by type and name specified in "foo.yaml" to 3.
  kubectl scale --replicas=3 -f foo.yaml
  
  # If the deployment named mysql''s current size is 2, scale mysql to 3.
  kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
  
  # Scale multiple replication controllers.
  kubectl scale --replicas=5 rc/foo rc/bar rc/baz
  
  # Scale statefulset named ''web'' to 3.
  kubectl scale --replicas=3 statefulset/web

6.3. 宿主机突发故障处理

假如 hdss7-21 突发故障,离线

  1. 其他运算节点上操作:先删除故障节点使 k8s 触发自愈机制,pod 在健康节点重新拉起
[root@hdss7-22 ~]#  kubectl delete node hdss7-21.host.com
node "hdss7-21.host.com" deleted
  1. 前端代理修改配置文件,把节点注释掉,使其不再调度到故障节点(hdss-7-21)
[root@hdss7-11 ~]# vi /etc/nginx/nginx.conf
[root@hdss7-11 ~]# vi /etc/nginx/conf.d/od.com.conf 
[root@hdss7-11 ~]# nginx -t 
[root@hdss7-11 ~]# nginx -s reload
  1. 节点修好,直接启动,会自行加到集群,修改 label,并把节点加回前端负载
[root@hdss7-21 bin]# kubectl label node hdss7-21.host.com node-role.kubernetes.io/master=
node/hdss7-21.host.com labeled
[root@hdss7-21 bin]# kubectl label node hdss7-21.host.com node-role.kubernetes.io/node=
node/hdss7-21.host.com labeled
[root@hdss7-21 bin]# kubectl get nodes
NAME                STATUS   ROLES         AGE   VERSION
hdss7-21.host.com   Ready    master,node   8d    v1.15.4
hdss7-22.host.com   Ready    master,node   10d   v1.15.4

6.4.FAQ

6.4.1.supervisor restart 不成功?

/etc/supervisord.d/xxx.ini 追加:

killasgroup=true
stopasgroup=true

docker for mac 安装 kubernetes、kubernetes dashboard

docker for mac 安装 kubernetes、kubernetes dashboard

  • 安装参考地址(按照此文档,安装成功):https://yq.aliyun.com/articles/508460

  • 官方说明:https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

  • 常用命令 kubectl 命令:

kubectl get namespaces
kubectl get pods --namespace kube-system
kubectl get deployments --namespace kube-system
kubectl get services --namespace kube-system
kubectl -n kube-system edit service kubernetes-dashboard
kubectl get pods
kubectl get deployments
kubectl get services
kubectl config view

获取令牌,然后登陆 kubernetes dashboard

➜  ~ kubectl get secrets
NAME                  TYPE                                  DATA      AGE
default-token-6ljm8   kubernetes.io/service-account-token   3         6h
➜  ~ kubectl describe secrets default-token-6ljm8
Name:         default-token-6ljm8
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name=default
              kubernetes.io/service-account.uid=77d014c2-0804-11e9-acd8-025000000001

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNmxqbTgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6Ijc3ZDAxNGMyLTA4MDQtMTFlOS1hY2Q4LTAyNTAwMDAwMDAwMSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.G9TGa4KGj5B-cMv-0-vuangR2_tFiQ1nJMgtsEPs1BEwPAyjmaC-BL5y0Ux9HyC1mlt0DklO-8_o41i4OD_w0wLymxi8zZQxgY7Tlu3_oE5OKnK58xWN-mMTKKnvfDpZrIBbkWQ5EB49LC7QiTBKGAoixGyOBvU1fmD2AzpdO3sWvNsaOWbMLFcwzHA-M2V-CKU3I07Hxs6uIi9juk4IqkTryfvCDUafTrubpkVktwQr7UwzvmKfbPoWLyn1tbCDhR3Il64daoTE9nlmqWwYZZFmfaZjWWWYfi3QPXuNUNpXRVVd_6gcjUzebR1o-22KoOUbobQ94K-1bYJOQSZNnA

将 token 部分复制到登录页的 token 输入框,登陆即可。 出处:http://www.cnblogs.com/along21/p/9811860.html#auto_id_11

Dubbo 3.0 前瞻之对接 Kubernetes 原生服务

Dubbo 3.0 前瞻之对接 Kubernetes 原生服务

Kubernetes 是当前全球最流行的容器服务平台,在 Kubernetes 集群中,Dubbo 应用的部署方式往往需要借助第三方注册中心实现服务发现。Dubbo 与 Kubernetes 的调度体系的结合,可以让原本需要管理两套平台的运维成本大大减低,而且 Dubbo 适配了 Kubernetes 原生服务也可以让框架本身更加融入云原生体系。基于 Dubbo 3.0 的全新应用级服务发现模型可以更容易对齐 Kubernetes 的服务模型。

Kubernetes Native Service

1.png

在 Kubernetes 中,Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。通常一个 Pod 由一个或多个容器组成,应用则部署在容器内。

对于一组具有相同功能的 Pod,Kubernetes 通过 Service 的概念定义了这样一组 Pod 的策略的抽象,也即是 Kubernetes Service。这些被 Kubernetes Service 标记的 Pod 一般都是通过 Label Selector 决定的。

在 Kubernetes Service 内,服务节点被称为 Endpoint,这些 Endpoint 也就是对应提供服务的应用单元,通常一对一对应了 Pod。

因此,我们可以将微服务中的应用本身使用 Service 来进行调度,而微服务间的调用通过 Service 的一系列机制来实现服务发现,进而将微服务整合进 Kubernetes Service 的体系中。

Dubbo 应用级服务发现

在 Dubbo 体系结构内,为了更好地符合 Java 开发人员的编程习惯,Dubbo 底层以接口粒度作为注册对象。但是这个模型对现在主流的 Spring Cloud 注册模型和 Kubernetes Service 注册模型有很大的区别。

目前在非 Dubbo 体系外的注册模型主要是以服务粒度作为注册对象,为了打通 Dubbo 与其他体系之间的注册发现壁垒,Dubbo 在 2.7.5 版本以后引入了服务自省的架构,主要通过元数据服务实现从服务粒度到接口粒度的过渡。在 2.7.5 版本以后到 3.0 版本,服务自省模型进行了很多方面的优化,并且在生产环境下进行了验证。

1. 元数据服务

2.png

元数据服务主要是存储了服务(Instance)与接口(Interface)的映射关系,通过将原本的写入到注册中心的接口信息抽象到元数据进行存储,一方面可以大大减少注册中心存储的数据量、降低服务更新时集群的网络通信压力,另一方面,实现了注册中心层面只存储应用粒度信息的目标,对齐了其他注册模型。

在服务自省模型中,服务提供者不仅仅往注册中心写入当前实例的信息,还需要往(本地或者远程的)元数据服务写入暴露的服务 URL 信息等;而对于服务消费者,在从注册中心获取实例信息后,还需要(通过 RPC 请求内建或者中心化配置中心获取)元数据服务获取服务提供者的服务 URL 信息等来生成接口粒度体系下的接口信息。

2. Revision 信息

3.png

Revision 信息是元数据服务引入的一种数据缓存机制,对于同一组应用很多情况下暴露的接口其实都是一样的,在进行服务(Instance)与接口(Interface)映射的时候会有许多重复的冗余数据,因此可以使用类似对元数据信息进行 MD5 计算的方式来对实例本身加上版本号,如果多个实例的版本号一致可以认为它们的元数据信息也一致,那么只需要随机选择一台来获取元数据信息即可,可以实现把通行量从一组实例都需要通信到只需要与一个实例通信的压缩。

如上图所示,服务消费者注册中心的工作机制可以总结为:

  • 服务消费者向注册中心获取服务实例列表。
  • 注册中心向服务消费者返回服务实例信息,在实例列表中包括了服务提供者向注册中心写入的 Revision 参数。
  • 服务消费者根据获取到实例信息的 Revision 参数进行分组,分别从每组实例中随机选择一台获取元数据服务。
  • 服务消费者通过 RPC 发起调用或者通过配置中心获取得到指定实例的元数据信息。
  • 服务消费者根据获取到的元数据信息组建接口粒度的服务信息。

关于应用级服务发现更多的信息可以参考:《Dubbo 迈出云原生重要一步 - 应用级服务发现解析》 image.gif

对接实现方式

本次实现的与 Kubernetes 对接的方式有两种,一种是通过 Kubernetes API Client 的形式获取信息,另外一种是通过 DNS Client 的形式获取。

1. Kubernetes API Client

Kubernetes 控制平面的核心是 API Server,API Server 提供了 HTTP API,以供用户、集群中的不同部分和集群外部组件相互通信。对于 Dubbo 来说,通过使用 Kubernetes API Client 便可以做到与 Kubernetes 控制平面通信。

1)Provider 侧细节

4.png

根据前文说到 Dubbo 应用级服务发现模型,对于 Provider 侧在应用启动、接口更新时需要向注册中心写入 Revision 信息,因此大致的逻辑如上图所示。

Label 标签作为 Selector 与 Service 进行匹配,Annotation 中则主要存储了 Revision 等信息,其中 Revision 信息需要由 Dubbo 应用主动向 Kubernetes API Server 发起更新请求写入,这也对应了服务注册的流程。

在目前版本的实现中,Kubernetes Service 的创建工作是交由运维侧实现的,也即是 Label Selector 是由运维侧去管理的,在 Dubbo 应用启动前就已经配置完毕了,Service 的名字也即是对应接口注解中的 Services 字段(对于不依赖任何第三方配置中心的需要在接口级别手动配置此字段)。

2)Consumer 侧细节

5.png

对于 Consumer 侧的逻辑大致上与应用级服务发现的模型设计的一样,在通过 API 获取到服务信息后通过获取对应 Pod 的 Annotation 信息补齐 ServiceInstance  信息,后续逻辑与服务自省一致。

3)优缺点

  • 需要指出的是,让应用本身直接与 Kubernetes 管理平台的 API 交互本身就存在一定安全隐患,如果配置不当有一定可能性导致拖垮整个 Kubernetes 集群。
  • 当应用大量更新时会给 Kubernetes API Server 带来一定压力。
  • 本方案直接将 Dubbo 的服务发现过程对接到 Kubernetes 集群的管理上,可以在 Kubernetes 环境下进一步简化管理的复杂度。

2. DNS Client

Kubernetes DNS 是 Kubernetes 提供的一种通过 DNS 查询的方式获取 Kubernetes Service 信息的机制,通过普通的 DNS 请求就可以获取到服务的节点信息。

1)全去中心化的元数据服务

由于 DNS 协议本身限制,目前并没有一个统一的较为简单的方式向 DNS 附加更多的信息用于写入 Revision 信息。对于 DNS 的实现方案我们将元数据服务进行了改造,使其不再强依赖往注册中心写入 Revision 信息,实现只需要知道 Dubbo 应用的 IP 即可以实现正常的服务发现功能。

6.png

改造后的元数据服务可以分为两大功能,一个是基于 revision 的获取 URL 信息等的能力,另外一个是获取对应 revision 的能力。Dubbo 服务消费者在通过注册中心获取到实例 IP 后会主动去与每一个实例的元数据服务进行连接,获取 revision 信息后,对于 revision 信息一致的实例随机选择一个去获取完整的元数据信息。 由于 Revision 信息采用了点对点的方式获取,当这个信息更新时要及时通知给消费者端进行更新。在当前版本的实现中,我们依赖了 参数回调 机制实现服务者主动推送给消费者。未来会基于 3.0 的全新 Triple 协议,实现流式推送。

2)Provider 侧细节

与 Kubernetes API Client 实现方式类似的,组建服务的过程均需要由运维侧进行,在服务提供者启动的时候会进行元数据信息本地缓存、对外暴露元数据服务接口的机制。

这里需要特别注意的是,为了使服务发现过程与业务服务本身解耦,元数据服务接口与业务接口对应的端口可以不一致,在使用 DNS 实现方案的时候全集群所有应用的元数据服务端口都需要统一, 通过 metadataServicePort 参数进行配置。这样亦可以适配那些不支持通过 SRV 获取端口的 DNS。

3)Consumer 侧细节

7.png

对于 DNS 注册中心来说,获取实例的流程主要通过向 DNS 发起 A (或 AAAA)查询请求来获取,而 Kubernetes DNS 也提供了 SRV 记录请求来获取服务的信息。

结合前文说到的全去中心化的元数据服务机制,Consumer 会去主动连接获取到的每一个实例的元数据服务,获取对应的 Revision 信息,同时以参数回调的形式向提供者提交回调函数用于更新本地信息。

在获取到 Revision 信息之后,对于具有相同 Revision 信息的实例,Dubbo 会随机选择其中一个获取完整元数据信息,至此完成服务发现的全过程。

4)优缺点

  • 本方案与前一种方案对比起来避免了 Kubernetes API 的直接交互,避免了交互的安全问题。
  • 由于 DNS 没有像 API Watch 的通知机制,只能采用轮询的方式判断服务的变更,在没有应用变更时集群内仍有一定量的 DNS 网络查询压力。
  • 本方案设计的时候目标是对任何只要能够通过 A (或 AAAA)查询获取到 Dubbo 应用本身的 IP 的 DNS 都可以适配,对 Kubernetes DNS 并不是强依赖关系。

总结

本次 Dubbo 对接 Kubernetes 原生服务是 Dubbo 往云原生化发展的一次尝试,未来我们将基于 xDS 协议实现与 Service Mesh 控制平面的交互,相关功能正在紧锣密鼓的筹划中。同时,在未来 Dubbo 3.0 的发版上,Java 社区和 Dubbo-go 社区将同步发版,本次 Kubernetes 的功能也将对齐上线。

系列文章推荐:

  • 《Dubbo 云原生之路:ASF 毕业一周年、3.0 可期》

  • 《Dubbo 迈出云原生重要一步 - 应用级服务发现解析》

  • 《Dubbo 3.0 前瞻:重塑 Spring Cloud 服务治理》

  • 《Dubbo 3.0 前瞻:常用协议对比及 RPC 协议新形态探索》

  • 《2020 双 11,Dubbo3.0 在考拉的超大规模实践》

  • 《Dubbo 3.0 前瞻系列:服务发现支持百万集群,带来可伸缩微服务架构》

  • 《Dubbo 版 Swagger 来啦!Dubbo-Api-Docs 发布》

作者简介

江河清,Github 账号 AlbumenJ,Apache Dubbo Committer。在读本科生,目前主要参与 Dubbo 社区云原生 Kubernetes 和 Service Mesh 模块对接。

dubbo 服务在 kubernetes 中对外暴露服务

dubbo 服务在 kubernetes 中对外暴露服务

一些场景下,在开发时可能存在 dubbo consumer 需要访问 k8s 中部署的 dubbo provider, 尤其是对于自建的 kubernetes 集群环境,tcp 的端口很难代理,这就导致了开发发链接集群内的服务比较麻烦,这里可以利用 service 将 dubbo 服务使用 nodeport 暴露出去,但是由于 dubbo 默认注册的 ip 地址是自动获取服务的 ip 地址来注册的,ip 地址是 pod 的 ip 地址,集群外是无法访问的。幸运的是 dubbo 提供了自动义指定注册 ip 的配置,我们可以在部署开发联调服务时指定 ip 地址为宿主机的 ip 地址。部署例子如下:

# -------------------Service ---------------------- #
apiVersion: v1
kind: Service
metadata:
 name: java-test-svc
 namespace: default
spec:
 type: NodePort
 ports:
 - port: 30011
   targetPort: 30011
   nodePort: 30011
 selector:
  app: java-test
  tier: backend
---
# ------------------- Deployment ------------------- #
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: java-test-deployment
  namespace: default
spec:
  selector:
      matchLabels:
        app: java-test
        tier: backend
  replicas: 1
  template:
    metadata:
      labels:
        app: java-test
        tier: backend
    spec:
      nodeSelector:
        dubbo_provder: dubbo_provider
      containers:
        - name: java-test
          image: [your image]
          imagePullPolicy: Always
#          resources:
#            requests:
#              cpu: 100m
#              memory: 100Mi
#            limits:
#              cpu: 100m
#              memory: 100Mi
          env:
              - name:  APOLLO_META
                value: http://172.31.205.22:8080
              - name: DUBBO_IP_TO_REGISTRY
                value: 172.31.205.23
              - name: DUBBO_PORT_TO_REGISTRY
                value: "30011"
              - name: DUBBO_PORT_TO_BIND
                value: "30011"
          ports:
            - containerPort: 30011
      imagePullSecrets:
      - name: harbor-key
---
# ------------------- ingress ---------------------- #
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: java-test-ingress
  namespace: default
spec:
  rules:
  - host: javatest.com
    http:
      #port: 80
      paths:
      - path: /
        backend:
          serviceName: java-test-svc
          servicePort: 30011

今天关于Dubbo 与 Kubernetes 集成dubbo集成sentinel的介绍到此结束,谢谢您的阅读,有关3、交付 Dubbo 微服务到 kubernetes 集群、docker for mac 安装 kubernetes、kubernetes dashboard、Dubbo 3.0 前瞻之对接 Kubernetes 原生服务、dubbo 服务在 kubernetes 中对外暴露服务等更多相关知识的信息可以在本站进行查询。

本文标签: