0%

有时候我们需要将k8s集群外的服务引入到集群内部来,便于集群内部服务调用,我可以使用Endpoints.

引入外部myql

编写k8s-mysql-endpoints.yaml

为外部Mysql创建Endpoints

apiVersion: v1
kind: Endpoints
metadata:
  name: mysql
  namespace: default
subsets:
  - addresses:
      - ip: 192.168.1.11
    ports:
      - port: 20030
  1. 可以使用命令kubectl get endpoints查看是否创建完成
  2. kubectl describe endpoints mysql 查看具体描述

编写k8s-mysql-service.yaml

编写k8s-mysql-service.yaml,为endpoints发布成内部pod可以调用的服务

注意metadata.namek8s-mysql-endpoints.yamlmetadata.name保持一致,此处均为mysql.

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 20030
  1. 可以使用命令 kubectl get svc 查看是否服务创建完成
  2. kubectl describe svc mysql 查看具体服务描述

测试endpoints是否生效

为了方便测试endpoints是否生效,我们修改上述的k8s-mysql-service.yaml配置

  1. 我们将type类型改为NodePort,这样可以设定宿主机上的映射端口号nodePort:30030,这样直接通过宿主机IP:30030就可以调用到mysql服务。
  2. 注意删除了创建好的service,对应的endpoints也会删除掉,需要重新创建!测试的时候注意!
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort
  ports:
  - port: 20030
    targetPort: 20030
    protocol: TCP
    nodePort: 30030

使用Navicat测试

使用Navicat测试,输入宿主机IP和端口30030(用户名密码还是外部数据库原本的用户名密码),测试连接!成功!证明了通过Endpoints机制可以将外部服务发布成k8s内部的服务!

发布外部的redis服务也是同理,只需要修改nameportip等参数即可!

consul具体配置、ACL配置可以参考Consul系列文章

首先创建k8s-consul-config.json文件

注意token需要自己创建一个,这里加密处理了

{
    "datacenter":"dc8",
    "primary_datacenter":"dc8",
    "acl":{
        "enabled":true,
        "default_policy":"deny",
        "enable_token_persistence":true,
        "enable_key_list_policy":true,
        "tokens":{
            "master":"14d54c5e-24ca-****-*******-*********"
        }
    }
}

创建configmap

kubectl  create configmap consul --from-file=k8s-consul-config.json

上述命令创建一个名称为consul,内容为一个文件,文件名为k8s-consul-config.jsonconfigmap可以挂载在volume下.

修改 k8s-consul-statefulset.yaml文件

注意内容:

  1. 在配置最后挂载了volumes-configmap,就是我们刚刚创建的consul
  2. - “-config-file=/etc/consul/config/k8s-consul-config.json” 配置了我们保存的consul ACL相关配置
  3. requiredDuringSchedulingIgnoredDuringExecution,我们增加了这个配置,保证了consul的pod不会在同一台机器上运行【反亲和特性】,因为我们将consul/data挂载的是hostPath,如果一台机器启动多个会有冲突导致consul启动卡住。
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: consul
spec:
  serviceName: consul
  replicas: 3
  template:
    metadata:
      labels:
        app: consul
        component: server
    spec:
      serviceAccountName: consul
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - consul
              topologyKey: kubernetes.io/hostname
      terminationGracePeriodSeconds: 10
      containers:
      - name: consul
        image: consul:1.6.0
        args:
          - "agent"
          - "-server"
          - "-bootstrap-expect=3"
          - "-ui"
          - "-data-dir=/consul/data"
          - "-config-file=/etc/consul/config/k8s-consul-config.json"
          - "-bind=0.0.0.0"
          - "-client=0.0.0.0"
          - "-advertise=$(PODIP)"
          - "-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-1.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-2.consul.$(NAMESPACE).svc.cluster.local"
          - "-domain=cluster.local"
          - "-disable-host-node-id"
        volumeMounts:
          - name: data
            mountPath: /consul/data
          - name: config
            mountPath: /etc/consul/config
        env:
          - name: PODIP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        ports:
          - containerPort: 8500
            name: ui-port
          - containerPort: 8400
            name: alt-port
          - containerPort: 53
            name: udp-port
          - containerPort: 8443
            name: https-port
          - containerPort: 8080
            name: http-port
          - containerPort: 8301
            name: serflan
          - containerPort: 8302
            name: serfwan
          - containerPort: 8600
            name: consuldns
          - containerPort: 8300
            name: server
      volumes:
        - name: data
          hostPath:
            path: /root/consul/data
        - name: config
          configMap:
            name: consul

最后根据上面的配置重新创建consul的StatefulSet,启动完成后根据之前consul的知识,我们需要使用master token登录到ui,创建Agent token,然后修改configmap中acl配置,增加agent token,具体可以参考之前的文章。然后删除consul的pod,让k8s重新创建新的pod,使我们新的configmap生效即可。

用途 命令
查看集群状态 kubectl cluster-info
查看集群详细状态 kubectl cluster-info dump
查看节点 kubectl get nodes
查看节点更多信息 kubectl get nodes -o wide
标志一个节点不可调度 kubectl cordon -nodeName
标志一个节点可调度 kubectl uncordon -nodeName
查看token列表 kubeadm token list
创建token kubeadm token create
删除节点 kubectl drain <node name> --delete-local-data --force --ignore-daemonsets/kubectl delete node <node name>
创建一个deployment kubectl create deployment nginx --image=nginx
查看deployments kubectl get deployment(deployments)
创建一个service kubectl create service nodeport nginx --tcp 80:80
查看services kubectl get svc(service/services)
删除一个deployment kubectl delete deployments/nginx
删除一个service kubectl delete services/nginx
同时删除deployment和service kubectl delete deployments/nginx services/nginx
从yaml文件创建deployment kubectl create -f deployment.yaml
查看pods kubectl get pods(pod)
查看pod更多信息 kubectl get pods -o wide
查看具体pod信息 kubectl describe pods/kube-node-59bf664cbf-2qzgd
修改deployment kubectl edit deployments/test
从yaml创建service kubectl create -f service.yaml
快捷创建service(expose) kubectl expose deployment kube-node --type=NodePort
查看service具体信息 kubectl describe services/kube-node
查看namespace kubectl get namespace
创建namespace kubectl create namespace -name
删除namespace kubectl delete namespace -name
根据配置文件创建configmap kubectl create configmap my-config --from-file=path/to/bar/kubectl create configmap my-config --from-file=key1=/path/file1.txt --from-file=key2=/path/to/bar/file2.txt
从字符串创建configmap kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
从env文件创建configmap kubectl create configmap my-config --from-env-file=path/to/bar.env
扩容 kubectl scale deployment nginx-deployment --replicas 10
自动扩容 kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
更新镜像 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
回滚 kubectl rollout undo deployment/nginx-deployment
查看默认配置项,如pod.spec kubectl explain pod.spec

以上都是亲自用过的,没用过的自己查表,附上kubectl命令表

kubectl命令自动补全

CentOS Linux系统上,您可能需要安装默认情况下未安装的bash-completion软件包。

yum install bash-completion -y

执行source <(kubectl completion bash)命令在您目前正在运行的shell中开启kubectl自动补全功能。

可以将上述命令添加到shell配置文件中,这样在今后运行的shell中将自动开启kubectl自动补全:

echo "source <(kubectl completion bash)" >> ~/.bashrc

快速生成YAML样例

# 用run命令生成
kubectl run --image=nginx my-deploy -o yaml --dry-run > my-deploy.yaml
# 用get命令导出
kubectl get statefulset/foo -o=yaml --export > new.yaml
# Pod亲和性下面字段的拼写忘记了
kubectl explain pod.spec.affinity.podAffinity

问题1:ip问题

consul
使用容器方式在主机上部署后,consul节点的ip为容器IP,如上图所示,主机外不能访问到该服务,需要配置内网或公网IP。

使用docker

使用docker run命令启动consul只需要在run后增加 --net = "host" ,这相当于使用主机上的IP。

#注意1是要指定net为host,2是网卡为主机上的网卡,该网卡主机外服务能访问到,可以使用ifconfig看看网卡具体的名字
docker run --net = "host" --name ** -e CONSUL_BIND_INTERFACE='eth0' ....(省略)

使用docker-compose

使用docker-compose启动docker,需要指定network_modehost

#原本配置,eth0为容器内网卡
  consul_server_2:
    container_name: consul_server_2
    image: consul:1.6.0
    networks: 
      consul:
        ipv4_address: 172.20.0.3
    volumes:
      - /docker/consul/server2/config:/consul/config
      - /docker/consul/server2/data:/consul/data
    environment:
      - CONSUL_BIND_INTERFACE=eth0
      - TZ=Asia/Shanghai
      - CONSUL_HTTP_TOKEN=db98c304-4d38-8660-fafe-6a4be56a40d0
    restart: always
    command: [
      'agent'
    ]
 
 
#优化后,映射端口不需要了,因为是直接使用主机ens33网卡了
  consul_server_1:
    container_name: consul_server_1
    image: consul:1.6.0
    network_mode: host
    volumes:
      - /docker/consul/server1/config:/consul/config
      - /docker/consul/server1/data:/consul/data
    environment:
      - CONSUL_BIND_INTERFACE=ens33
      - TZ=Asia/Shanghai
      - CONSUL_HTTP_TOKEN=db98c304-4d38-8660-fafe-6a4be56a40d0
    restart: always
    command: [
      'agent'
    ]

这样启动后consul服务的ip会变成主机的ip,外面的服务可以访问,跨机器部署consul集群通信也不会有问题了
consul

但是以上办法一台机器只能启动一个consul容器,多了会有端口占用的问题,如果想要单机部署多个consul节点,可以考虑修改consul端口。

//新增ports.json放到consul的配置目录下即可。配置目录下所有.json配置都会加载
//默认端口参考官网:https://www.consul.io/docs/agent/options.html#ports
{
  "ports": {
    "dns":9600,
    "http":9500,
    "serf_lan":9301,
    "serf_wan":9302,
    "server":9300
  }
}

启动后同一台机器上两个consul都启动了,占用不同端口,类似可以继续增加consul节点数量,他们的IP都是一样的

consul
consul

问题2:跨机器加入集群报错

#client
2019/10/11 03:48:01 [INFO] agent: (LAN) joining: [192.168.41.128]
consul_client_2    | ==> 1 error occurred:
consul_client_2    | 	* Failed to join 192.168.41.128: No installed keys could decrypt the message
 
#server端
consul_server_1    |     2019/10/11 03:48:18 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48362
consul_server_1    |     2019/10/11 03:48:18 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48364
consul_server_1    |     2019/10/11 03:48:31 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48438
consul_server_1    |     2019/10/11 03:48:31 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48440
consul_server_1    |     2019/10/11 03:48:57 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48598
consul_server_1    |     2019/10/11 03:48:57 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48600
所有consul节点加入配置
"encrypt":"Cwqvm4elg0SIaF6xanFxZ3OFYadEiQtZ71xY1mJTUbk="
 
此encrypt官方解释是用与集群通信加密的,生成方式 consul keygen
 
依然报错不能解决
//所有节点加入以下配置,删除encrypt,下面的配置字面意思,出入的通信都不在验证,问题解决,不在报错
    "encrypt_verify_incoming":false
    "encrypt_verify_outgoing":false

上面的配置是把验证功能关掉了,有安全隐患,官网还有另一个配置disable_keyring_file,(https://github.com/hashicorp/consul/issues/4163)有人可以解决,但是我尝试没有成功,后面继续研究有没有两全其美的办法。。

start_join、retry_join的格式

-join-启动时要加入的另一个代理的地址。可以多次指定,以指定要加入的多个代理。如果Consul无法加入任何指定地址,则代理启动将失败。默认情况下,代理在启动时不会加入任何节点。请注意,retry_join在Consul群集部署自动化时,使用 更为合适的方法有助于减轻节点启动竞争条件。
 
 
-retry-join-与类似,-join但如果第一次尝试失败,则允许重试连接。在您知道该地址最终可用的情况下,这很有用。该列表可以包含IPv4,IPv6或DNS地址。在Consul 1.1.0及更高版本中,可以将其设置为 go-sockaddr 模板。如果Consul在非默认的Serf LAN端口上运行,则也必须指定此端口。IPv6必须使用“括弧式”语法。如果给出了多个值,则按照列出的顺序尝试并重试它们,直到第一个成功。这里有些例子:
 
# Using a DNS entry
$ consul agent -retry-join "consul.domain.internal"
 
# Using IPv4,只有IP
$ consul agent -retry-join "10.0.4.67"
 
# Using IPv6,带端口
$ consul agent -retry-join "[::1]:8301"
 
#配置文件中格式
    "start_join":[
        "192.168.41.128:8301"
    ],
    "retry_join":[
        "192.168.41.128:8301"
    ],

问题:No installed keys could decrypt the message 报错解决

新加入的consul节点需要配置encrypt,这个值是需要跟server端一样的,值保存在/consul/data/serf/local.keyring文件中,如果文件中已存在内容,是不是会更新的,需要删掉,或者手动填入,然后重启服务。如果文件中已经有了,那么启动配置中encrypt参数就可以删了,不会产生影响。-disable-keyring-file这个参数作用是是否持久化这个encrypt,默认持久化,可以选择不持久化,缺点是就要在启动配置里显式填写,优点是更好的排查所有节点是否一样。例如文件中和你启动参数中不一样,问题就出来了。

可以先在原有的集群中找到local.keyring文件中找到该encrypt,所有节点保持一致即可。

重点:

consul的配置需要全部写在resource目录下bootstrap.yml文件中,写在application.yml中不能生效!

consul config配置

#bootstrap.yml配置
spring:
  cloud:
    consul:
      host: 192.168.1.11
      port: 8500
      config:
        enabled: true
        format: KEY_VALUE
        data-key: data
        watch:
          enabled: true
        prefix: deriii
        acl-token: bd63ce16-ccd0-22e1-d37d-fb948232cbf5
      discovery:
        healthCheckPath: /actuator/health
        healthCheckInterval: 15s
        acl-token: bd63ce16-ccd0-22e1-d37d-fb948232cbf5
        prefer-ip-address: true
        ip-address: 192.168.1.113

获取配置

    //data在consul中完整的目录是prefix + application name + data  
    @Value("${data}")
    String test;
 
    @RequestMapping("/test")
    public String test() {
        return test;
    }

实时刷新,需要在类上加注解

@RefreshScope

另一种实现配置刷新

#bootstrap.yml配置,主要是修改了format为YAML,配合spring boot Configuration使用
spring:
  cloud:
    consul:
      host: 192.168.1.11
      port: 8500
      config:
        enabled: true
        format: YAML
        data-key: data
        watch:
          enabled: true
        prefix: deriiiii
        acl-token: bd63ce16-ccd0-22e1-d37d-fb948232cbf5
      discovery:
        healthCheckPath: /actuator/health
        healthCheckInterval: 15s
        acl-token: bd63ce16-ccd0-22e1-d37d-fb948232cbf5
        prefer-ip-address: true
        ip-address: 192.168.1.113

spring boot 配置类

@ConfigurationProperties(prefix = "ttt")
@Configuration
public class HiConfig {
 
    private String test;
 
    //getter setter ...
}

consul中key为prefix + application Name + data,value为yaml类型,且前缀是ttt,属性名为test

#key = deriiii/service-hello/data
ttt:
 test: asdas

启动类加上

@EnableConfigurationProperties({HiConfig.class})

全局配置

http头部加入X-Consul-Token,值为有权限的token

查询一个key值

#key=/data
http://192.168.1.11:8500/v1/kv/data
 
#key=/test/data
http://192.168.1.11:8500/v1/kv/test/data

查询一个folder下所有key值

#folder是test,注意test后面有/不能少!
http://192.168.1.11:8500/v1/kv/test/?recurse=true

查询folder下有哪些key

#test后面有/
http://192.168.1.11:8500/v1/kv/test/?keys

修改key值

注意:KV存储中的值不能大于512kb

#使用PUT请求,key为/test/data
http://192.168.1.11:8500/v1/kv/test/data
 
#body可以是
{
  "data":"sasasaasas1231313131"
}
 
#或者是
{
  "data-binary":"sasasaasas6666666"
}
 
#修改成功则回复true

删除key

#使用DELETE请求,key为/test/data
http://192.168.1.11:8500/v1/kv/test/data
 
#成功则返回true