Spring Cloud 中间件在 Kubernetes 上的最佳实践

前提说明

  1. 业务程序使用 Spring Cloud 框架开发

  2. 如果采用离线部署的方式,所有相关镜像需要提前 push 到镜像仓库,本文略过

  3. 部署架构图

  1. 整体部署架构涉及的中间件包含以下组件

    • Nacos

    • RocketMQ

    • Redis

    • xxl-job

    • SkyWalking

    • MySQL

    • Nginx

  2. 部署架构说明

    • K8s 集群之外采用了 Nginx 作为网关代理,将外部流量引入 K8s 集群

    • K8s 集群对外暴露服务使用了 NodePort 的方式,暂时没有引入 Ingress(因为不会,后期学会了再引入)

    • 其他的中间件都是部署在 K8s 集群之内

    • 本文并没有写日志配置的相关内容,后续会有专门的文档介绍

    • 本文没有介绍业务模块的配置内容,相关内容会在业务模块自动化发布文档中专门介绍

网关代理安装配置

环境说明

  • 操作系统 CentOS7.9

  • Nginx 1.20.2 的 RPM 包

部署步骤

# 下载rpm离线包,这里选择官方的最新稳定版1.20.2
$ wget http:/nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.20.2-1.el7.ngx.x86_64.rpm

# 安装
$ rpm -ivh nginx-1.20.2-1.el7.ngx.x86_64.rpm
warning: nginx-1.20.2-1.el7.ngx.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 7bd9bf62: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:nginx-1:1.20.2-1.el7.ngx         ################################# [100%]

# 查看已安装的nginx
$ rpm -qa | grep nginx
nginx-1.20.2-1.el7.ngx.x86_64

# 根据需要修改/etc/nginx/nginx.conf(主要用于自定义nginx服务器的各种配置等)
$ vi /etc/nginx/nginx.conf
示例配置见配置文件参考

# 根据需要修改/etc/nginx/conf.d/***.conf(主要用于自定义nginx的各种转发规则等)
$ vi /etc/nginx/conf.d/***.conf
示例配置见配置文件参考

# 检测nginx配置文件
$ nginx -t

# 启动nginx,并配置开机自启
$ systemctl start nginx && systemctl enable nginx

配置文件参考

  1. nginx.conf (/etc/nginx/nginx.conf)

    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;

    Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.

    include /usr/share/nginx/modules/*.conf;

    events {
    worker_connections 10240;
    }

    http {
    server_tokens off; # 隐藏版本号
    client_header_timeout 60; # 客户端向服务端发送一个完整的 request header 的超时时间。如果客户端在指定时间内没有发送一个完整的 request header,Nginx 返回 HTTP 408(“Request timed out”)
    client_body_timeout 60; # 该指令设置请求正文即请求体(request body)的读超时时间。超时仅设置为两个连续读取操作之间的时间段,而不是整个请求主体的传输。如果客户端在此时间内未传输任何内容,请求将以408(请求超时)错误终止
    limit_conn_zone KaTeX parse error: Expected 'EOF', got '#' at position 49: … #̲ 限制可以存储多少个并发连接数…remote_addr - r e m o t e u s e r [ remote_user [ remoteuser[time_local] “KaTeX parse error: Double superscript at position 34: … '̲status b o d y b y t e s s e n t " body_bytes_sent " bodybytessent"http_referer” ’
    ‘“ h t t p u s e r a g e n t " " http_user_agent" " httpuseragent""http_x_forwarded_for”’;

    log_format  debug  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"debug-cors" $cors_origin "debug-origin" $http_origin ';
    
    access_log  /var/log/nginx/access.log  main;
    
    sendfile            on;                                            # sendfile 是个比 read 和 write 更高性能的系统接口, 不过需要注意的是,sendfile 是将 in_fd 的内容发送到 out_fd 。而 in_fd 不能是 socket , 也就是只能文件句柄。所以当 Nginx 是一个静态文件服务器的时候,开启 SENDFILE 配置项能大大提高 Nginx 的性能.
    tcp_nopush          on;                                            # 可以配置一次发送数据包的大小。也就是说,数据包累积到一定大小后就发送,tcp_nopush 必须和 sendfile 配合使用.
    tcp_nodelay         on;                                            # 会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果
    types_hash_max_size 4096;                                        # nginx 使用了一个散列表来保存MIME type 与文件扩展名之间的映射,该参数就是指定该散列表桶的大小的
    
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    error_page  400 404 413 502 504  /index.html;
    
    # 开启 gzip 压缩
    gzip  on;
    # 不压缩临界值,大于 1K 的才压缩
    gzip_min_length 1k;
    # buffer
    gzip_buffers 4 16k;
    # 用了反向代理的话,末端通信是 HTTP/1.0,默认是 HTTP/1.1
    #gzip_http_version 1.0;
    # 压缩级别,1-10,数字越大压缩的越好,时间也越长
    gzip_comp_level 2;
    # 进行压缩的文件类型,缺啥补啥
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascriptapplication/x-httpd-php image/jpeg image/gif image/png;
    # 跟 Squid 等缓存服务有关,on 的话会在 Header 里增加 "Vary: Accept-Encoding"
    gzip_vary off;
    # IE6 对 Gzip 不友好,不进行 Gzip 压缩
    gzip_disable "MSIE [1-6].";
    
    client_max_body_size 100m;                                    # nginx 对上传文件大小的限制
    proxy_buffer_size  128k;                                    # Nginx 使用该大小申请 read_buf,即大小指定了 upstream header 最大长度,如果响应头超过了这个长度,Nginx 会报 upstream sent too big header 错误,然后 client 收到的是 502
    proxy_buffers   32 32k;                                        # 设置存储被代理服务器响应的 body 所占用的 buffer 个数和每个 buffer 大小
    proxy_busy_buffers_size 128k;                                # proxy_busy_buffers_size 不是独立的空间,他是 proxy_buffers 和 proxy_buffer_size 的一部分。nginx 会在没有完全读完后端响应就开始向客户端传送数据,所以它会划出一部分 busy 状态的 buffer 来专门向客户端传送数据(建议为 proxy_buffers 中单个缓冲区的 2 倍),然后它继续从后端取数据。proxy_busy_buffer_size 参数用来设置处于 busy 状态的 buffer 有多大
    
    fastcgi_buffers 16 256k;                                    # 设定用来读取从 FastCGI 服务器端收到的响应信息的缓冲区大小和缓冲区数量
    fastcgi_buffer_size 128k;                                    # Nginx FastCGI 的缓冲区大小,用来读取从 FastCGI 服务器端收到的第一部分响应信息的缓冲区大小
    fastcgi_busy_buffers_size 256k;                                # 用于设置系统很忙时可以使用的 proxy_buffers 大小
    
    map $http_upgrade $connection_upgrade {  # 开启 websocket 升级代理功能,可选
        default upgrade;
        '' close;
    }
    
    include /etc/nginx/conf.d/*.conf;
    
    server {                                                    # http(80)转 https(443)配置
        listen       80;
        listen       [::]:80;
        server_name  www.abc.com;
        rewrite ^(.*)$ https://${server_name}$1 permanent;
        #root         /usr/share/nginx/html;
    
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
    
        error_page 404 /404.html;
        location = /404.html {
        }
    
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
    

    }

  2. default.conf(/etc/nginx/conf.d/default.conf)

配置文件里只是一个后端模块的配置,请根据实际情况增加对应的 location

server {
listen 80;
  server_name www.abcd.com;
   access_log  /var/log/nginx/abc.access.log  main;                # 自定义专属日志文件
  
  location / {
    root /usr/share/nginx/dist;
    index  index.html index.htm;
  }

    location ^~ /api/ {                                            # 转发示例
        proxy_pass http://192.168.1.1:8003/;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

K8s 部署 MySQL5.7

Nacos 需要使用 MySQL 存储配置数据,由于使用量不大,因此没有考虑高可用部署,也可以采用已有的 MySQL 数据库。

部署步骤

创建 MySQL 相关部署文件

  1. 创建 MySQL 存储 PVCyaml 文件

    $ vi mysql-pvc.yaml

  • mysql-pvc.yaml

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
    name: mysql-pvc
    namespace: test #注意修改命名空间
    spec:
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: 10Gi
    storageClassName: glusterfs

  1. 创建 MySQL 配置 configmap yaml 文件

    $ vi mysql-config.yaml

  • mysql-config.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: mysql-cm
    namespace: test #注意修改命名空间
    data:
    mysqld.cnf: |
    [mysqld]
    pid-file = /var/run/mysqld/mysqld.pid
    socket = /var/run/mysqld/mysqld.sock
    datadir = /var/lib/mysql
    bind-address = 0.0.0.0
    port = 3306
    log-bin = mysql-bin
    server-id = 1

  1. 创建 MySQL 服务 Service yaml 文件

    $ vi mysql-service.yaml

  • mysql-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
    name: mysql
    namespace: test #注意修改命名空间
    spec:
    type: NodePort
    ports:

    • port: 3306
      targetPort: 3306
      nodePort: 30850
      selector:
      app: mysql
  1. 创建 MySQL 配置副本 Deployment yaml 文件

    $ vi mysql.yaml

  • mysql.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: mysql
    namespace: test #注意修改命名空间
    spec:
    selector:
    matchLabels:
    app: mysql
    template:
    metadata:
    labels:
    app: mysql
    spec:
    containers:
    - name: mysql
    image: mysql:5.7.32
    env:
    - name: MYSQL_ROOT_PASSWORD
    value: “root@my.123” #数据库root的密码
    ports:
    - containerPort: 3306
    volumeMounts:
    - name: mysql-persistent-storage
    mountPath: /var/lib/mysql
    volumeMounts:
    - name: mysql-config
    mountPath: /etc/mysql/mysql.conf.d/mysqld.cnf
    subPath: mysqld.cnf
    volumes:
    - name: mysql-persistent-storage
    persistentVolumeClaim:
    claimName: mysql-pvc
    - name: mysql-config
    configMap:
    name: mysql-cm

部署 MySQL

$ kubectl apply -f mysql-pvc.yaml
$ kubectl apply -f mysql-config.yaml
$ kubectl apply -f mysql-service.yaml
$ kubectl apply -f mysql.yaml

验证 MySQL

$ kubectl get pods -n test
NAME                     READY   STATUS    RESTARTS   AGE
mysql-589dcf6597-5ps6x   1/1     Running   0          8m3s

# 进入pod登录验证
$ kubectl exec -it mysql-589dcf6597-5ps6x /bin/bash -n test
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@mysql-589dcf6597-5ps6x:/# mysql -u root -p
Enter password:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'P@ssword-123';        #修改root密码
Query OK, 0 rows affected (0.00 sec)

K8s 部署 Nacos 集群

部署步骤

拉取项目代码

#拉取nacos代码
$ git clone https://github.com/nacos-group/nacos-K8s.git

#拉取nacos的初始化数据库sql文件
$ wget https://github.com/alibaba/nacos/blob/develop/distribution/conf/nacos-mysql.sql

创建 Nacos 所需数据库

# 登录数据库
$ kubectl exec -it mysql-589dcf6597-5ps6x /bin/bash -n test
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@mysql-589dcf6597-5ps6x:/# mysql -u root -p
Enter password:
# 创建数据库
mysql> CREATE DATABASE  IF NOT EXISTS `nacos_dev` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;

# 创建nacos用户
mysql> GRANT ALL PRIVILEGES ON  nacos.* to nacos@'%' IDENTIFIED BY 'nacos';

# 刷新权限
mysql> FLUSH PRIVILEGES;

# 导入nacos数据库
mysql> use nacos;
Database changed

# 查看mysql的连接端口
$ kubectl get svc -n test
NAME                                                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mysql                                                    NodePort    10.233.20.110   <none>        3306:30850/TCP   47m

# 使用mysql连接工具连接数据库并导入上方sql
# 因为mysql service的类型为nodeport,所以连接地址为任一K8s集群的节点ip地址,端口为30850

# 回到命令行查看nacos数据表
mysql> show tables;
+----------------------+
| Tables_in_nacos      |
+----------------------+
| config_info          |
| config_info_aggr     |
| config_info_beta     |
| config_info_tag      |
| config_tags_relation |
| group_capacity       |
| his_config_info      |
| permissions          |
| roles                |
| tenant_capacity      |
| tenant_info          |
| users                |
+----------------------+
12 rows in set (0.00 sec)

修改 Nacos 部署 yaml 文件

#进入项目目录
$ cd nacos-K8s/deploy/nacos
$ cp nacos-pvc-nfs.yaml nacos.yaml

# 修改部署文件
[root@K8s-master-0 nacos]# vi nacos.yaml
  • nacos.yaml

    — #修改8848端口为nodeport形式,以便集群外部访问
    apiVersion: v1
    kind: Service
    metadata:
    name: nacos-server
    namespace: test #增加命名空间
    labels:
    app: nacos
    annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: “true”
    spec:
    type: NodePort
    ports:
    - port: 8848
    name: server
    targetPort: 8848
    nodePort: 30848
    selector:
    app: nacos

    apiVersion: v1
    kind: Service
    metadata:
    name: nacos-headless
    namespace: test #增加命名空间
    labels:
    app: nacos
    annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: “true”
    spec:
    ports:
    - port: 8848
    name: server
    targetPort: 8848
    - port: 9848
    name: client-rpc
    targetPort: 9848
    - port: 9849
    name: raft-rpc
    targetPort: 9849
    ## 兼容1.4.x版本的选举端口
    - port: 7848
    name: old-raft-rpc
    targetPort: 7848
    clusterIP: None
    selector:
    app: nacos

    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: nacos-cm
    namespace: test #增加命名空间
    data:
    mysql.host: “mysql.test” #增加mysql连接地址
    mysql.db.name: “nacos_devtest”
    mysql.port: “3306”
    mysql.user: “nacos”
    mysql.password: “nacos”

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: nacos
    namespace: test #增加命名空间
    spec:
    serviceName: nacos-headless
    replicas: 3
    template:
    metadata:
    labels:
    app: nacos
    annotations:
    pod.alpha.kubernetes.io/initialized: “true”
    spec:
    affinity:
    podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
    matchExpressions:
    - key: “app”
    operator: In
    values:
    - nacos
    topologyKey: “kubernetes.io/hostname”
    initContainers:
    - name: peer-finder-plugin-install
    image: nacos/nacos-peer-finder-plugin:1.1
    imagePullPolicy: Always
    volumeMounts:
    - mountPath: /home/nacos/plugins/peer-finder
    name: data
    subPath: peer-finder
    containers:
    - name: nacos
    imagePullPolicy: Always
    image: nacos/nacos-server:latest
    resources:
    requests:
    memory: “2Gi”
    cpu: “500m”
    ports:
    - containerPort: 8848
    name: client-port
    - containerPort: 9848
    name: client-rpc
    - containerPort: 9849
    name: raft-rpc
    - containerPort: 7848
    name: old-raft-rpc
    env:
    - name: NACOS_REPLICAS
    value: “3”
    - name: SERVICE_NAME
    value: “nacos-headless”
    - name: DOMAIN_NAME
    value: “cluster.local” #修改K8s集群地址,可通过cat /etc/kubernetes/kubelet.conf查看对应字段:contexts/- context/cluster
    - name: POD_NAMESPACE
    valueFrom:
    fieldRef:
    apiVersion: v1
    fieldPath: metadata.namespace
    - name: MYSQL_SERVICE_HOST #增加获取mysql连接地址的环境变量
    valueFrom:
    configMapKeyRef:
    name: nacos-cm
    key: mysql.host
    - name: MYSQL_SERVICE_DB_NAME
    valueFrom:
    configMapKeyRef:
    name: nacos-cm
    key: mysql.db.name
    - name: MYSQL_SERVICE_PORT
    valueFrom:
    configMapKeyRef:
    name: nacos-cm
    key: mysql.port
    - name: MYSQL_SERVICE_USER
    valueFrom:
    configMapKeyRef:
    name: nacos-cm
    key: mysql.user
    - name: MYSQL_SERVICE_PASSWORD
    valueFrom:
    configMapKeyRef:
    name: nacos-cm
    key: mysql.password
    - name: NACOS_SERVER_PORT
    value: “8848”
    - name: NACOS_APPLICATION_PORT
    value: “8848”
    - name: PREFER_HOST_MODE
    value: “hostname”
    volumeMounts:
    - name: data
    mountPath: /home/nacos/plugins/peer-finder
    subPath: peer-finder
    - name: data
    mountPath: /home/nacos/data
    subPath: data
    - name: data
    mountPath: /home/nacos/logs
    subPath: logs
    volumeClaimTemplates:
    - metadata:
    name: data
    namespace: test #增加命名空间
    annotations:
    volume.beta.kubernetes.io/storage-class: “managed-nfs-storage”
    spec:
    accessModes: [ “ReadWriteMany” ]
    storageClassName: “glusterfs” #增加storageClass选择器,以便自动创建pvc
    resources:
    requests:
    storage: 20Gi
    selector:
    matchLabels:
    app: nacos

部署集群

$ kubectl apply  -f  nacos.yaml

验证集群

# 查看nacos pod
$ kubectl get pod -n test | grep nacos
nacos-0                                               1/1     Running   0          120d
nacos-1                                               1/1     Running   0          120d
nacos-2                                               1/1     Running   0          120d

# 查看nacos svc
$ kubectl get svc -n test | grep nacos
NAME                               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                               AGE
nacos-headless                     ClusterIP   None            <none>        8848/TCP,9848/TCP,9849/TCP,7848/TCP   216d
nacos-server                       NodePort    10.233.20.35    <none>        8848:30848/TCP                        213d

# 访问任意节点ip+30848(nodeport端口)进行验证 http://ip:30848/nacos
默认用户名/密码 :nacos/nacos

K8s 部署 Redis 集群

Redis 采用三主三从集群模式部署

部署步骤

创建 Redis 副本文件

$ vi redis-statefulset.yaml
  • redis-statefulset.yaml


    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: redis-cluster-cm
    namespace: test
    data:
    redis-conf: |
    appendonly yes #开启AOF模式
    protected-mode no #关闭protected-mode模式,此时外部网络可以直接访问
    cluster-enabled yes #开启集群模式
    cluster-config-file /data/nodes.conf #Redis集群节点的集群配置文件
    cluster-node-timeout 5000 #指节点在失败状态下必须不可到达的毫秒数。大多数其他内部时间限制是节点超时的倍数
    dir /data #数据存储目录
    port 6379
    requirepass redis@123.com #redis密码,自定义
    masterauth redis@123.com #如果master是密码保护的,在启动复制同步进程之前,可以告诉奴隶进行身份验证,否则主人将拒绝奴隶请求。

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: redis
    namespace: test
    labels:
    app: redis
    spec:
    serviceName: redis-headless
    replicas: 6
    selector:
    matchLabels:
    app: redis
    template:
    metadata:
    labels:
    app: redis
    spec:
    affinity:
    podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
    podAffinityTerm:
    labelSelector:
    matchExpressions:
    - key: app
    operator: In
    values:
    - redis
    topologyKey: kubernetes.io/hostname
    containers:
    - name: redis
    image: dockerhub.test.com:18443/library/redis:6.2.5
    command:
    - “redis-server”
    args:
    - “/etc/redis/redis.conf”
    - “–protected-mode”
    - “no”
    - “–cluster-announce-ip”
    - “$(POD_IP)”
    env:
    - name: POD_IP
    valueFrom:
    fieldRef:
    fieldPath: status.podIP
    ports:
    - name: redis
    containerPort: 6379
    protocol: “TCP”
    - name: cluster
    containerPort: 16379
    protocol: “TCP”
    volumeMounts:
    - name: redis-conf
    mountPath: /etc/redis
    - name: redis-data
    mountPath: /data
    volumes:
    - name: redis-conf
    configMap:
    name: redis-cluster-cm
    items:
    - key: redis-conf
    path: redis.conf
    volumeClaimTemplates:
    - metadata:
    name: redis-data
    namespace: test
    spec:
    accessModes: [ “ReadWriteOnce” ]
    storageClassName: “glusterfs” #注意修改为自己的storageClass
    resources:
    requests:
    storage: 10Gi #pvc容量,自定义


    apiVersion: v1
    kind: Service
    metadata:
    name: redis-headless
    namespace: test
    labels:
    app: redis
    spec:
    type: NodePort
    ports:
    - name: redis-port
    port: 6379
    targetPort: 6379
    nodePort: 30849 #nodeport端口自定义
    selector:
    app: redis

部署并配置集群

# 部署
$ kubectl apply -f redis-statefulset.yaml

# 配置集群
# 自动配置3个master,3个slave节点的集群,-a指定密码
$ kubectl exec -it redis-0 -n test -- redis-cli -a redis@123.com --cluster create --cluster-replicas 1 $(kubectl get pods -n test -l app=redis -o jsonpath='{range.items[*]}{.status.podIP}:6379 {end}')

验证集群

# 对redis集群进行验证
$ kubectl exec -it redis-0 -n test -- redis-cli -a redis@123.com --cluster check $(kubectl get pods -n test -l app=redis -o jsonpath='{range.items[0]}{.status.podIP}:6379{end}')
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.233.67.76:6379 (b8e966ed...) -> 286 keys | 5461 slots | 1 slaves.
10.233.94.207:6379 (31d925a7...) -> 263 keys | 5462 slots | 1 slaves.
10.233.98.106:6379 (11b42330...) -> 275 keys | 5461 slots | 1 slaves.
[OK] 824 keys in 3 masters.
0.05 keys per slot on average.
>>> Performing Cluster Check (using node 10.233.67.76:6379)
M: b8e966ed2e00d2c9fb24ebdd409fd7eef90cbb11 10.233.67.76:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 35d46c8a708f234b73d647d1a800e52a620f2fbd 10.233.82.103:6379
   slots: (0 slots) slave
   replicates 31d925a76d8276ec6b1735a65b3e8d238ca5b63f
S: 8bbb3e01a5d9087327ff5ea2ee57e87c772c5ba9 10.233.94.205:6379
   slots: (0 slots) slave
   replicates 11b42330416a1fe3da01ff696b573e35f95be0c6
M: 31d925a76d8276ec6b1735a65b3e8d238ca5b63f 10.233.94.207:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 11b42330416a1fe3da01ff696b573e35f95be0c6 10.233.98.106:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 121cdf362ae961cb18df31588df56e2e0cd42f10 10.233.123.249:6379
   slots: (0 slots) slave
   replicates b8e966ed2e00d2c9fb24ebdd409fd7eef90cbb11
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

$ kubectl get pod -n test | grep redis
redis-0                                               1/1     Running   0          130d
redis-1                                               1/1     Running   0          130d
redis-2                                               1/1     Running   0          130d
redis-3                                               1/1     Running   0          130d
redis-4                                               1/1     Running   0          130d
redis-5                                               1/1     Running   0          130d

K8s 部署 RocketMQ 集群

  • 为了实现快速和简单的部署,RocketMQ 的部署采用了官方提供的 Operator

  • 但是官方的部署使用后期发现诸多不便之处,也可能是我没玩明白,还需要深入研究

    • pod 如果重建的话 UI 可能会连不上集群

    • pod 重建后集群发现也出现过问题

部署步骤

部署 RocketMQ 相关组件的 CRD 资源

# 拉取rocketmq部署文件
$ git clone -b 0.2.1 https://github.com/apache/rocketmq-operator.git
$ cd rocketmq-operator

# 查看crd部署脚本
$ cat install-operator.sh
#!/bin/bash

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

kubectl create -f deploy/crds/rocketmq_v1alpha1_broker_crd.yaml
kubectl create -f deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml
kubectl create -f deploy/crds/rocketmq_v1alpha1_topictransfer_crd.yaml
kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/operator.yaml
# kubectl create -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml


# 为部署脚本中的所有yaml文件增加命名空间
$ vi deploy/crds/rocketmq_v1alpha1_broker_crd.yaml
apiVersion: apiextensions.K8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: brokers.rocketmq.apache.org
  namespace: test

$ vi deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml
apiVersion: apiextensions.K8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: nameservices.rocketmq.apache.org
  namespace: test

$ vi deploy/crds/rocketmq_v1alpha1_consoles_crd.yaml
apiVersion: apiextensions.K8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: consoles.rocketmq.apache.org
  namespace: test

$ vi deploy/crds/rocketmq_v1alpha1_topictransfer_crd.yaml
apiVersion: apiextensions.K8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: topictransfers.rocketmq.apache.org
  namespace: test

$ vi deploy/service_account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rocketmq-operator
  namespace: test

$ vi deploy/role.yaml
apiVersion: rbac.authorization.K8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: rocketmq-operator
  namespace: test

$ vi deploy/role_binding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.K8s.io/v1
metadata:
  name: rocketmq-operator
  namespace: test

$ vi deploy/operator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rocketmq-operator
  namespace: test

# 创建rocketmq Operator
$ sh install-operator.sh
Warning: apiextensions.K8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.K8s.io/v1 CustomResourceDefinition
customresourcedefinition.apiextensions.K8s.io/brokers.rocketmq.apache.org created
Warning: apiextensions.K8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.K8s.io/v1 CustomResourceDefinition
customresourcedefinition.apiextensions.K8s.io/nameservices.rocketmq.apache.org created
Warning: apiextensions.K8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.K8s.io/v1 CustomResourceDefinition
customresourcedefinition.apiextensions.K8s.io/topictransfers.rocketmq.apache.org created
serviceaccount/rocketmq-operator created
role.rbac.authorization.K8s.io/rocketmq-operator created
rolebinding.rbac.authorization.K8s.io/rocketmq-operator created
deployment.apps/rocketmq-operator created

# 查看rocketmq Operator
$ kubectl get pod -n test
NAME                               READY   STATUS    RESTARTS   AGE
rocketmq-operator-867c4955-dhgzh   1/1     Running   0          7m40s

配置 RocketMQ 集群部署 yaml 文件

$ vi example/rocketmq_v1alpha1_rocketmq_cluster.yaml
  • rocketmq_v1alpha1_rocketmq_cluster.yaml

    Licensed to the Apache Software Foundation (ASF) under one or more

    contributor license agreements. See the NOTICE file distributed with

    this work for additional information regarding copyright ownership.

    The ASF licenses this file to You under the Apache License, Version 2.0

    (the “License”); you may not use this file except in compliance with

    the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software

    distributed under the License is distributed on an “AS IS” BASIS,

    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

    See the License for the specific language governing permissions and

    limitations under the License.

    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: broker-config
    namespace: test #添加命名空间
    data:

    BROKER_MEM sets the broker JVM, if set to “” then Xms = Xmx = max(min(1/2 ram, 1024MB), min(1/4 ram, 8GB))

    BROKER_MEM: " -Xms2g -Xmx2g -Xmn1g "
    broker-common.conf: |
    # brokerClusterName, brokerName, brokerId are automatically generated by the operator and do not set it manually!!!
    deleteWhen=04
    fileReservedTime=48
    flushDiskType=ASYNC_FLUSH
    # set brokerRole to ASYNC_MASTER or SYNC_MASTER. DO NOT set to SLAVE because the replica instance will automatically be set!!!
    brokerRole=ASYNC_MASTER


    apiVersion: rocketmq.apache.org/v1alpha1
    kind: Broker
    metadata:

    name of broker cluster

    name: broker
    namespace: test #添加命名空间
    spec:

    size is the number of the broker cluster, each broker cluster contains a master broker and [replicaPerGroup] replica brokers.

    size: 1

    nameServers is the [ip:port] list of name service

    nameServers: “” #无需填写自动获取

    replicaPerGroup is the number of each broker cluster

    replicaPerGroup: 1

    brokerImage is the customized docker image repo of the RocketMQ broker

    brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine-operator-0.3.0

    imagePullPolicy is the image pull policy

    imagePullPolicy: Always

    resources describes the compute resource requirements and limits

    resources:
    requests:
    memory: “2048Mi”
    cpu: “250m”
    limits:
    memory: “12288Mi”
    cpu: “500m”

    allowRestart defines whether allow pod restart

    allowRestart: true

    storageMode can be EmptyDir, HostPath, StorageClass

    storageMode: StorageClass

    hostPath is the local path to store data

    hostPath: /data/rocketmq/broker

    scalePodName is [Broker name]-[broker group number]-master-0

    scalePodName: broker-0-master-0

    env defines custom env, e.g. BROKER_MEM

    env:
    - name: BROKER_MEM
    valueFrom:
    configMapKeyRef:
    name: broker-config
    key: BROKER_MEM

    volumes defines the broker.conf

    volumes:
    - name: broker-config
    configMap:
    name: broker-config
    items:
    - key: broker-common.conf
    path: broker-common.conf

    volumeClaimTemplates defines the storageClass

    volumeClaimTemplates:
    - metadata:
    name: broker-storage
    spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: “glusterfs” #修改为自己的storageClass
    resources:
    requests:
    storage: 8Gi #可自定义pvc容量

    apiVersion: rocketmq.apache.org/v1alpha1
    kind: NameService
    metadata:
    name: name-service
    namespace: test #添加命名空间
    spec:

    size is the the name service instance number of the name service cluster

    size: 1

    nameServiceImage is the customized docker image repo of the RocketMQ name service

    nameServiceImage: apacherocketmq/rocketmq-nameserver:4.5.0-alpine-operator-0.3.0

    imagePullPolicy is the image pull policy

    imagePullPolicy: Always

    hostNetwork can be true or false

    hostNetwork: true

    Set DNS policy for the pod.

    Defaults to “ClusterFirst”.

    Valid values are ‘ClusterFirstWithHostNet’, ‘ClusterFirst’, ‘Default’ or ‘None’.

    DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.

    To have DNS options set along with hostNetwork, you have to specify DNS policy

    explicitly to ‘ClusterFirstWithHostNet’.

    dnsPolicy: ClusterFirstWithHostNet

    resources describes the compute resource requirements and limits

    resources:
    requests:
    memory: “512Mi”
    cpu: “250m”
    limits:
    memory: “1024Mi”
    cpu: “500m”

    storageMode can be EmptyDir, HostPath, StorageClass

    storageMode: StorageClass

    hostPath is the local path to store data

    hostPath: /data/rocketmq/nameserver

    volumeClaimTemplates defines the storageClass

    volumeClaimTemplates:
    - metadata:
    name: namesrv-storage
    spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: rocketmq-storage
    storageClassName: “glusterfs” #修改为自己的storageClass
    resources:
    requests:
    storage: 1Gi #可自定义pvc容量


    apiVersion: rocketmq.apache.org/v1alpha1
    kind: Console
    metadata:
    name: console
    namespace: test #添加命名空间
    spec:

    nameServers is the [ip:port] list of name service

    nameServers: “”

    consoleDeployment define the console deployment

    consoleDeployment:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: rocketmq-console
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: rocketmq-console
    template:
    metadata:
    labels:
    app: rocketmq-console
    spec:
    containers:
    - name: console
    image: apacherocketmq/rocketmq-console:2.0.0
    ports:
    - containerPort: 8080

配置 RocketMQ 集群 Service yaml 文件

$ vi example/rocketmq_v1alpha1_cluster_service.yaml
  • rocketmq_v1alpha1_cluster_service.yaml

    Licensed to the Apache Software Foundation (ASF) under one or more

    contributor license agreements. See the NOTICE file distributed with

    this work for additional information regarding copyright ownership.

    The ASF licenses this file to You under the Apache License, Version 2.0

    (the “License”); you may not use this file except in compliance with

    the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software

    distributed under the License is distributed on an “AS IS” BASIS,

    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

    See the License for the specific language governing permissions and

    limitations under the License.

    apiVersion: v1
    kind: Service
    metadata:
    name: console-service
    namespace: test #修改命名空间
    labels:
    app: rocketmq-console
    spec:
    type: NodePort
    selector:
    app: rocketmq-console
    ports:
    - port: 8080
    targetPort: 8080
    protocol: TCP
    nodePort: 30849 #注意修改nodeport端口
    #—
    #apiVersion: v1 #如果集群外的服务需要使用rockermq可以取消此service注释
    #kind: Service
    #metadata:

    name: name-server-service

    namespace: test

    #spec:

    type: NodePort

    selector:

    name_service_cr: name-service

    ports:

    - port: 9876

    targetPort: 9876

    # use this port to access the name server cluster

    nodePort: 30001

    #—

部署集群

# 安装rocketmq集群
$ kubectl apply -f example/rocketmq_v1alpha1_rocketmq_cluster.yaml

# 安装rocketmq集群service
$ kubectl apply -f example/rocketmq_v1alpha1_cluster_service.yaml

验证集群

# 查看rocketmq集群pod
$ kubectl get pod -n test
NAME                               READY   STATUS    RESTARTS   AGE
broker-0-master-0                  1/1     Running   0          13m
broker-0-replica-1-0               1/1     Running   0          13m
console-fd66cc958-t7twh            1/1     Running   0          13m
name-service-0                     1/1     Running   0          13m
rocketmq-operator-867c4955-dhgzh   1/1     Running   0          13m

# 查看rocketmq集群svc
$ kubectl get svc -n test
NAME                                                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
console-service                                          NodePort    10.233.46.31    <none>        8080:30849/TCP   12m
glusterfs-dynamic-0fc569c2-e2fe-4ef1-be6a-b3d56f1058d1   ClusterIP   10.233.36.32    <none>        1/TCP            15h
glusterfs-dynamic-ceed9eef-7264-45c5-b727-4afc64ab34ab   ClusterIP   10.233.60.200   <none>        1/TCP            16h
glusterfs-dynamic-e7c85113-e164-4423-a5ad-99f7c3f8b0f1   ClusterIP   10.233.24.21    <none>        1/TCP            15h
rocketmq-operator                                        ClusterIP   10.233.61.255   <none>        8383/TCP         13m

# 查看rocketmq集群pvc
$ kubectl get pvc -n test
NAME                                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
broker-storage-broker-0-master-0      Bound    pvc-e7c85113-e164-4423-a5ad-99f7c3f8b0f1   8Gi        RWO            glusterfs      15h
broker-storage-broker-0-replica-1-0   Bound    pvc-0fc569c2-e2fe-4ef1-be6a-b3d56f1058d1   8Gi        RWO            glusterfs      15h
namesrv-storage-name-service-0        Bound    pvc-ceed9eef-7264-45c5-b727-4afc64ab34ab   10Gi       RWO            glusterfs      16h

# 浏览器访问nodeip+console-service的nodeport端口进行验证
# http://ip:30849/

K8s 部署 XXL-JOB

部署步骤

创建 XXL-JOB 所需数据库

# 数据库sql参考地址包含创建数据库步骤,见附录
$ wget https://github.com/xuxueli/xxl-job/blob/master/doc/db/tables_xxl_job.sql
#查看mysql的连接端口
$ kubectl get svc -n test
NAME                                                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mysql                                                    NodePort    10.233.20.110   <none>        3306:30850/TCP   47m

# 使用mysql连接工具连接数据库并导入上方sql,因为mysql service的类型为nodeport,所以连接地址为任一K8s集群的节点ip地址,端口为30850
# 以下创建用户操作也可以再连接工具中操作
# 登录数据库
$ kubectl exec -it mysql-589dcf6597-5ps6x /bin/bash -n test
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@mysql-589dcf6597-5ps6x:/# mysql -u root -p
Enter password:

mysql> create user 'xxl'@'%' identified by 'P@ssw0rd@xxl';                #创建xxl用户用于xxl-job服务连接
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON  xxl_job.* TO 'xxl'@'%' IDENTIFIED BY 'P@ssw0rd@xxl';     #对xxl用户授权
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;                                    #刷新权限
Query OK, 0 rows affected (0.00 sec)

创建 XXL-JOB 的副本 yaml 文件

$ vi xxl-job.yaml
  • xxl-job.yaml

    kind: Deployment
    apiVersion: apps/v1
    metadata:
    name: xxl-job
    namespace: test
    labels:
    app: xxl-job
    annotations:
    deployment.kubernetes.io/revision: ‘6’
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: xxl-job
    template:
    metadata:
    creationTimestamp: null
    labels:
    app: xxl-job
    annotations:
    cni.projectcalico.org/ipv4pools: ‘[“default-ipv4-ippool”]’
    spec:
    containers:
    - name: container-e0tn05
    image: ‘xuxueli/xxl-job-admin:2.3.0’
    ports:
    - name: tcp-8080
    containerPort: 8080
    protocol: TCP
    env:
    - name: PARAMS
    value: >-
    –spring.datasource.url=jdbc:mysql://mysql.test:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    –spring.datasource.username=xxl
    –spring.datasource.password=P@ssw0rd@xxl
    –xxl.job.accessToken=RfCwgzKLuRGbrqqN9Tg9WT3t #注意修改数据库连接地址端口及用户密码
    resources:
    limits:
    cpu: ‘4’
    memory: 8000Mi
    requests:
    cpu: 500m
    memory: 500Mi
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    imagePullPolicy: IfNotPresent
    restartPolicy: Always
    terminationGracePeriodSeconds: 30
    dnsPolicy: ClusterFirst
    serviceAccountName: default
    serviceAccount: default
    securityContext: {}
    affinity: {}
    schedulerName: default-scheduler
    strategy:
    type: RollingUpdate
    rollingUpdate:
    maxUnavailable: 25%
    maxSurge: 25%
    revisionHistoryLimit: 10
    progressDeadlineSeconds: 600

创建 XXL-JOB 的 Service yaml 文件

$ vi xxl-job-service.yaml
  • xxl-job-service.yaml

    kind: Service
    apiVersion: v1
    metadata:
    name: test-xxl-job-service
    namespace: test
    labels:
    app: test-xxl-job-service
    spec:
    ports:
    - name: http-8080
    protocol: TCP
    port: 8080
    targetPort: 8080
    nodePort: 30850
    selector:
    app: test-xxl-job
    type: NodePort
    sessionAffinity: None
    externalTrafficPolicy: Cluster

创建 XXL-JOB

# 部署xxl_job副本
$ kubectl apply -f  xxl-job.yaml

# 部署xxl_job服务svc
$ kubectl apply -f  xxl-job-service.yaml

验证 XXL-JOB

# 查看xxl-job的pod
$ kubectl get pod -n test

# 查看xxl-job的svc
$ kubectl get svc -n test

# 浏览器访问任一节点ip+30850(nodeport端口)进行验证
# http://ip:30850/xxl-job-admin/
# 默认用户名/密码 :admin/123456

K8s 部署 SkyWalking

部署步骤

创建 SkyWalking 的配置 yaml 文件

$ vi skywalking-cm.yaml
  • skywalking-cm.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: skywalking-cm
    namespace: test
    data:
    STORAGE: ‘elasticsearch7’
    STORAGE_ES_CLUSTER_NODES: ‘...:9200’ #es的连接地址
    ES_USER: ‘****’ #es的用户名
    ES_PASSWORD: ‘********’ #es的密码
    CORE_GRPC_PORT: ‘11800’
    CORE_REST_PORT: ‘12800’

创建 SkyWalking 的副本 yaml 文件

$ vi skywalking-deployment.yaml
  • skywalking-deployment.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: skywalking
    name: test-skywalk-skywalking-oap
    namespace: test
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: skywalking
    template:
    metadata:
    labels:
    app: skywalking
    spec:
    containers:
    - envFrom:
    - prefix: SW_
    configMapRef:
    name: skywalking-cm
    image: apache/skywalking-oap-server:8.7.0-es7
    imagePullPolicy: IfNotPresent
    name: skywalking
    ports:
    - containerPort: 12800
    name: http
    protocol: TCP
    - containerPort: 11800
    name: grpc
    protocol: TCP
    resources:
    limits:
    cpu: ‘2’
    memory: 2Gi
    requests:
    cpu: ‘1’
    memory: 2Gi
    volumeMounts:
    - mountPath: /etc/localtime
    name: volume-localtime
    volumes:
    - hostPath:
    path: /etc/localtime
    type: ‘’
    name: volume-localtime

创建 SkyWalking 的 Service yaml 文件

$ vi skywalking-deployment.yaml
  • skywalking-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
    name: test-skywalk-skywalking-oap
    namespace: test
    labels:
    app: skywalking
    spec:
    type: ClusterIP
    ports:
    - name: http
    port: 12800
    protocol: TCP
    targetPort: 12800
    - name: grpc
    port: 11800
    protocol: TCP
    targetPort: 11800
    selector:
    app: skywalking

创建 SkyWalking-ui 副本的 Service yaml 文件

$ vi skywalking-ui-service.yaml
  • skywalking-ui-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
    name: skywalking-ui
    labels:
    app: skywalking-ui
    namespace: test
    spec:
    type: ClusterIP
    ports:
    - name: http
    port: 8080
    protocol: TCP
    targetPort: 8080
    selector:
    app: skywalking-ui

创建 SkyWalking-ui 的副本 yaml 文件

$ vi skywalking-ui.yaml
  • skywalking-ui.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: skywalking-ui
    name: skywalking-ui
    namespace: test
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: skywalking-ui
    template:
    metadata:
    labels:
    app: skywalking-ui
    spec:
    containers:
    - env:
    - name: SW_OAP_ADDRESS
    value: “skywalking:12800”
    image: apache/skywalking-ui:8.9.1
    imagePullPolicy: IfNotPresent
    name: skywalking-ui
    ports:
    - containerPort: 8080
    name: http
    protocol: TCP
    resources:
    limits:
    cpu: ‘2’
    memory: 1Gi
    requests:
    cpu: ‘1’
    memory: 1Gi
    volumeMounts:
    - mountPath: /etc/localtime
    name: volume-localtime
    volumes:
    - hostPath:
    path: /etc/localtime
    type: ‘’
    name: volume-localtime

部署安装 SkyWalking

$ kubectl apply -f skywalking-cm.yaml
$ kubectl apply -f skywalking-deployment.yaml
$ kubectl apply -f skywalking-service.yaml
$ kubectl apply -f skywalking-ui-service.yaml
$ kubectl apply -f skywalking-ui.yaml

验证 SkyWalking

# 查看SkyWalking副本
$ kubectl get pod -n test
NAME                                                  READY   STATUS    RESTARTS   AGE
skywalking-ui-7cb7f68686-4sgtq                        1/1     Running   0          22d
test-skywalk-skywalking-oap-67f6cd45fd-dm7d4          1/1     Running   0          22d
test-skywalk-skywalking-oap-67f6cd45fd-ggg4z          1/1     Running   0          22d

# 查看SkyWalking service
$ kubectl get svc -n test
NAME                                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                               AGE
skywalking-ui                           NodePort    10.233.16.121   <none>        8080:30849/TCP                        22d
test-skywalk-skywalking-oap             ClusterIP   10.233.12.1     <none>        12800/TCP,11800/TCP                   22d

# 使用浏览器访问任意节点ip+30849(nodeport端口)进行验证
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值