分布式健值存储etcd 3.1.7

 阅读约 24 分钟

资源

特性

  • 键值对存储引擎,协议消息使用protobuf
  • 最新版本3.1.5
  • 3.x 版本和 2.x版本 不兼容 3.x是2.x性能的2倍以上,3.x使用gRPC代替了2.x的JSON;etcd3中的租约替代了etc2的TTL;etcd3的事务原子性并发
  • 用于分布式网络、服务发现、配置管理、任务调度和负载均衡
  • 单实例可达每秒 1000 次写操作
  • 一个三成员 etcd 集群在轻负载下可以在低于1毫秒内完成一个请求,并在重负载下可以每秒完成超过 30000 个请求。
  • 支持 SSL 客户端证书认证加密请求
  • v2和v3 的API使用不同的存储引擎,两个版本的操作的都是自己的数据 。所以要用v3的api
  • 默认存储大小为2GB数据、配置启动参数 --quota-backend-bytes 可以最高到8GB。默认每次请求保存的key最大为1MB。
  • ETCD V3不再使用目录结构,只保留键。例如:”/a/b/c/“是一个键,而不是目录。V3中提供了前缀查询,来获取符合前缀条件的所有键值,这变向实现了V2中查询一个目录下所有子目录和节点的功能。
  • 简洁的响应:像DELETE这类操作成功后将不再返回操作前的值。如果希望获得删除前的值,可以使用事务,来实现一个原子操作,先获取键值,然后再删除。
  • 租约:租约代替了V2中的TTL实现,TTL绑定到一个租约上,键再附加到这个租约上。当TTL过期时,租约将被销毁,同时附加到这个租约上的键也被删除。

概念

  • 初始化的问题 如果集群第一次初始化启动的时候,有一台节点未启动,通过v3的接口访问的时候,会报告Error: Etcdserver: not capable 错误。这是为兼容性考虑,集群启动时默认的API版本是2.3,只有当集群中的所有节点都加入了,确认所有节点都支持v3接口时,才提升集群版本到v3。这个只有第一次初始化集群的时候会遇到,如果集群已经初始化完毕,再挂掉节点,或者集群关闭重启(关闭重启的时候会从持久化数据中加载集群API版本),都不会有影响
  • grpc-gateway网关 etcd v3使用gRPC作为其消息协议。此网关提供RESTful代理,将HTTP / JSON请求转换为gRPC消息。

安装

mkdir -p /opt/etcd-v3.1.7
  curl -sSL http://aliacs-k8s.oss-cn-hangzhou.aliyuncs.com/common/etcd-v3.1.7-linux-amd64.tar.gz| tar xz --strip-components=1 -C /opt/etcd-v3.1.7
  ln -sf /opt/etcd-v3.1.7/etcd /usr/bin/etcd
  ln -sf /opt/etcd-v3.1.7/etcdctl /usr/bin/etcdctl
  etcd --version

mkdir -p /var/lib/etcd;mkdir -p /etc/etcd; groupadd -r etcd; useradd -r -g etcd -d /var/lib/etcd -s /sbin/nologin -c "etcd user" etcd;chown -R etcd:etcd /var/lib/etcd
  
  cat << EOT > /lib/systemd/system/etcd.service
[Unit]
Description=etcd service
After=network.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
User=etcd
ExecStart=/usr/bin/etcd --data-dir=data.etcd --name dudu_etcd_245 \
  --initial-advertise-peer-urls http://10.99.73.245:2380 --listen-peer-urls http://10.99.73.245:2380 \ 
  --advertise-client-urls http://10.99.73.245:2379 --listen-client-urls http://10.99.73.245:2379 \
  --initial-cluster dudu_etcd_245=http://10.99.73.245:2380,dudu_etcd_246=http://10.99.73.246:2380 \ 
  --initial-cluster-state new --initial-cluster-token etcd-cluster-dudu-docker
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOT
  
  systemctl daemon-reload
  systemctl enable etcd
  systemctl start etcd
  systemctl status -l etcd.service
  
  检查集群健康
  ETCDCTL_API=3 etcdctl endpoint health --endpoints=10.31.75.198:2379,10.29.164.118:2379
  

常用操作命令

  • etcdctl 命令文件是客户端操作入口 ;使用前设置环境变量 ETCDCTL_API=3 使用3版本的api默认是2版本的
  • export ETCDCTL_API=3

配置

  • 启动参数:

    • --listen-client-urls :监听客户端通讯的URL列表可以是 0.0.0.0:2379 任何来源 127.0.0.1:2379 本机 以及指定IP
    • --listen-peer-urls : 用于监听伙伴通讯的URL列表 0.0.0.0:2380 任何来源 127.0.0.1:2380 本机 以及指定IP
    • --data-dir: 日志快照文件保存目录
    • --name: 成员名 必须唯一
    • --initial-advertise-peer-urls:集群。列出这个成员的伙伴 URL 以便通告给集群的其他成员,集群可访问的本机地址
    • --advertise-client-urls:集群。列出这个成员的客户端URL,通告给集群中的其他成员。
    • --initial-cluster-token: 集群唯一名
    • --initial-cluster: 集群成员列表;etcd_node_1=http://10.29.167.233:2380,etcd_node_2=http://10.29.168.24:2380
    • --initial-cluster-state:集群状态,值为 new or existing,new创建静态或DNS集群,existing 加入现有集群
    • --auto-compaction-retention:自动压缩用于 mvcc 键值存储的保持力(注:应该指多版本保存),单位小时。 0 表示关闭自动压缩默认为0关闭 对于服务注册等只保存运行时动态信息的场合,建议开启。完全没有理由损失存储空间和效率来保存之前的版本信息。推荐设置为1,每小时压缩一次。
  • 集群启动
  • 容器集群启动

    #编辑Dockerfile文件
    #Version:1.0                                                        
    FROM alpine:3.5
    MAINTAINER kingcarrot 294865887@qq.com
    #更新日期
    ENV REFRESHED_AT 2017-04-13
    
    #环境变量 启动容器命令-e参数修改环境变量
    #添加目录
    #ADD /home/ngrok/data/ /home/data/
    
    WORKDIR /bin
    #USER root
    RUN  apk add --update ca-certificates openssl  tzdata && \
            cp -r -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
            echo "Asia/Shanghai" >  /etc/timezone && \
            apk del --purge  openssl && \
            rm -Rf /var/cache/apk/*
    #添加文件
    COPY  etcd* etcdctl*  /bin/
    
    #挂载目录
    VOLUME  /data
    #开放端口
    EXPOSE 2379 2380
    
    #启动命令
    ENTRYPOINT  ["/bin/etcd","--data-dir=/data"]
    
    #构建镜像
    docker build -t dudu_etcd:v2 .
    #运行容器  第一个运行的节点就是master主机 
    docker run -d -p 2379:2379 -p 2380:2380 --restart=always -v /home/etcd_data:/data --name dudu_etcd_0 dudureg.xip.io:5000/dudu_etcd:v3.0.17 --name etcd_node_0 \
    --initial-advertise-peer-urls http://10.29.167.233:2380 --listen-peer-urls http://0.0.0.0:2380  \
    --advertise-client-urls http://10.29.167.233:2379 --listen-client-urls http://0.0.0.0:2379 \
    --initial-cluster-state new --initial-cluster-token kubernetes_etcd_token_test --auto-compaction-retention=0 \
    --initial-cluster etcd_node_0=http://10.29.167.233:2380,etcd_node_1=http://10.29.167.233:2381,etcd_node_2=http://10.29.167.233:2382
    
    docker run -d -p 2378:2379 -p 2381:2380 --restart=always -v /home/etcd_data_1:/data --name dudu_etcd_1 dudureg.xip.io:5000/dudu_etcd:v3.0.17 --name etcd_node_1 \
    --initial-advertise-peer-urls http://10.29.167.233:2381 --listen-peer-urls http://0.0.0.0:2380  \
    --advertise-client-urls http://10.29.167.233:2378 --listen-client-urls http://0.0.0.0:2379 \
    --initial-cluster-state new --initial-cluster-token kubernetes_etcd_token_test --auto-compaction-retention=0  \
    --initial-cluster etcd_node_0=http://10.29.167.233:2380,etcd_node_1=http://10.29.167.233:2381,etcd_node_2=http://10.29.167.233:2382
    
    docker run -d -p 2377:2379 -p 2382:2380 --restart=always -v /home/etcd_data_2:/data --name dudu_etcd_2 dudureg.xip.io:5000/dudu_etcd:v3.0.17 --name etcd_node_2 \
    --initial-advertise-peer-urls http://10.29.167.233:2382 --listen-peer-urls http://0.0.0.0:2380  \
    --advertise-client-urls http://10.29.167.233:2377 --listen-client-urls http://0.0.0.0:2379 \
    --initial-cluster-state new --initial-cluster-token kubernetes_etcd_token_test --auto-compaction-retention=0 \
    --initial-cluster etcd_node_0=http://10.29.167.233:2380,etcd_node_1=http://10.29.167.233:2381,etcd_node_2=http://10.29.167.233:2382
    
    #容器中 --listen-peer-urls http://0.0.0.0:2380 --listen-client-urls http://0.0.0.0:2379 配置 才能被容器外访问,但相当于完全开放出去了,访问宿主服务器ip 同样能访问到etcd;
    #配置为127.0.0.1 容器外部却无法访问;配置为宿主IP则无法启动etcd;可以配置阿里云的服务器安全组拒绝外网对2379和2380的端口访问
    # --initial-cluster 集群多成员时,必须全部启动才能访问,否则只配置本机为成员就可以单机访问
    
    
    #查看日志 
    docker logs -f -t --tail=100 dudu_etcd_1
    docker exec -ti dudu_etcd_1 ash 
    export ETCDCTL_API=3 | /bin/etcdctl version
  • 安装图形化监控报警工具 Prometheus
  • https://prometheus.io/docs/in... 官网

    PROMETHEUS_VERSION="1.3.1"
    wget https://github.com/prometheus/prometheus/releases/download/v$PROMETHEUS_VERSION/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz -O /tmp/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz
    tar -xvzf /tmp/prometheus-$PROMETHEUS_VERSION.linux-amd64.tar.gz --directory /tmp/ --strip-components=1
    /tmp/prometheus -version
    
    #配置监控的集群
    cat > /tmp/test-etcd.yaml <<EOF
      global:
        scrape_interval: 10s
      scrape_configs:
        - job_name: test-etcd
          static_configs:

EOF
cat /tmp/test-etcd.yaml

#启动成后台进程 每10秒收集一次数据
nohup /tmp/prometheus \

-config.file /tmp/test-etcd.yaml \
-web.listen-address ":9090" \
-storage.local.path "test-etcd.data" >> /tmp/test-etcd.log  2>&1 &

#Grafana 内置了Prometheus的支持
只需要添加一个数据源
Name: test-etcd
Type: Prometheus
Url: http://localhost:9090
Access: proxy


## 功能

### REST API 请求 都是v2版本的api
* curl http://localhost:2379/version
* curl http://localhost:2379/metrics  监控
* curl http://localhost:2379/health   节点健康存活
* curl http://localhost:2379/v2/stats/leader  查看领导主机状态
* curl http://localhost:2379/v2/stats/self   查看当前节点自身状态
* curl http://localhost:2379/v2/stats/store   存储状态
* curl http://localhost:2379/v2/members  成员列表
* curl http://localhost:2379/v2/members -XPOST -H "Content-Type: application/json" -d '{"peerURLs":["http://10.0.0.10:2380"]}' 添加成员
* curl http://localhost:2379/v2/members/272e204152 -XDELETE 删除成员
* curl http://localhost:2379/v2/members/272e204152 -XPUT -H "Content-Type: application/json" -d '{"peerURLs":["http://10.0.0.10:2380"]}' 更改
* curl http://localhost:2379/v2/keys/message -XPUT -d value="Hello world" 添加健值message=Hello world
* curl http://localhost:2379/v2/keys/message  获取健值
* curl http://localhost:2379/v2/keys/message -XPUT -d value="Hello etcd" 更改健值
* curl http://localhost:2379/v2/keys/message -XDELETE 删除健值
* curl http://localhost:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5  设置健值生存期
* curl http://localhost:2379/v2/keys/foo?wait=true  持久监视健值变化
* curl http://localhost:2379/v2/keys/dir -XPUT -d dir=true  创建一个目录 v3版本没有目录概念
* curl http://localhost:2379/v2/keys/  列出目录
* curl http://localhost:2379/v2/keys/foo_dir?dir=true -XDELETE 清空目录
* curl http://localhost:2379/v2/keys/dir?recursive=true -XDELETE 删除目录

### v3版本的API
* 注意:key和value 的值必须是base64编码之后的字符串 无需传参的数据还是必须是空json的body体 和必须是POST请求类型
* https://coreos.com/etcd/docs/3.1.5/dev-guide/apispec/swagger/rpc.swagger.json  所有的接口定义
* https://coreos.com/etcd/docs/3.1.5/dev-guide/api_reference_v3.html#service-cluster-etcdserveretcdserverpbrpcproto 接口文档
* https://github.com/coreos/etcd/blob/8fdfac2843f68144d4cc0d74713a036316b1fd45/etcdserver/etcdserverpb/rpc.proto  源代码查看接口
* curl -L http://localhost:2379/v3alpha/kv/put     -X POST -d '{"key": "Zm9v", "value": "YmFy"}'  设置值
* curl -L http://localhost:2379/v3alpha/kv/range -X POST -d '{"key": "Zm9v"}'  查看指定范围的健值
* curl -L http://localhost:2379/v3alpha/watch  -X POST -d '{"create_request": {"key":"Zm9v"} }' &  监视健值的变化
* curl -L http://localhost:2379/v3alpha/cluster/member/list -X POST -d '{}'  查看成员列表
* curl -L http://localhost:2379/v3alpha/kv/deleterange -X POST -d '{"key": "Zm9v"}' 删除指定范围的数据

### etcdctl 命令请求
* docker exec -ti dudu_etcd_0 ash 
* export ETCDCTL_API=3 使用命令之前确定使用的API版本默认是2
* etcdctl version  版本
* etcdctl 命令 --endpoints=10.30.187.25:2379 加上请求地址参数
* etcdctl member list --endpoints=10.30.187.25:2379 集群成员;列出成员ID,集群的peerURLs参数和集群的clientURLs参数
* etcdctl cluster-health 集群健康
* etcdctl member update a8266ecf031671f3 http://10.0.1.10:2380  更新节点peerURLs
* etcdctl member remove a8266ecf031671f3 删除节点 
* etcdctl member add etcd_node_3 http://10.0.1.13:2380  新增节点
* etcdctl put keys "{aa:1, bb: 2}" --endpoints=10.30.187.25:2379  保存键值
* etcdctl get keys  获取键值
* etcdctl get --endpoints=10.30.187.25:2379 --prefix=true ""  获取所有值
* etcdctl get --prefix=true "/kubernetes" 获取指定前缀的所有健值
* etcdctl del keys  删除健值
* etcdctl del --endpoints=10.30.187.25:2379 --prefix=true "/kubernetes"  删除指定前缀的所有健值返回删除数量
* etcdctl watch keys  监视健值
* etcdctl compaction 压缩历史数据  etcd支持历史数据的读取,为了避免积累无限历史数据。compacting操作后,etcd将删除历史的版本数据,释放资源为后面使用。在compacted 版本前的数据都将无效。
* etcdctl defrag    对指定成员碎片整理
* etcdctl snapshot save  backup.db 保存快照
* etcdctl snapshot status backup.db 快照状态
* etcdctl snapshot restore  backup.db 从指定文件恢复快照
* etcdctl --endpoints=127.0.0.1:2379 endpoint status  查看状态

## 维护
* https://coreos.com/etcd/docs/3.1.5/upgrades/upgrade_3_1.html  3.0升级到3.1 零停机,滚动升级
* 升级集群主机,建议一次升级一个成员,停止master是可以的,但会有短暂的选举停顿
* 要替换健康的单个成员,请添加一个新成员,然后删除旧成员
* 维持在三个成员配置集群
* etcdctl --write-out=table endpoint status  节点状态查看
* etcdctl alarm list    查看警告列表

## 调试

## 优化
* 容器时区配置问题:

ls -l /etc/localtime 主机上查看本地时区

yaml文件中将本地时区文件加载到pod容器中/etc/localtime
volumeMounts:

  - name: tz-config
    mountPath: /etc/localtime
volumes:
  - name: tz-config
    hostPath:
       path: /usr/share/zoneinfo/Asia/Shanghai

单容器配置指定时区
docker run -it --rm -e "TZ=Asia/Shanghai" centos:7 date +%Z



## 常见问题
阅读 888发布于 2018-12-17
推荐阅读
一天一练
用户专栏

原理、概念、算法、设计模式、C、Lua、Python、PHP、Go、Java、JavaScript、Linux等。每天练习

1 人关注
10 篇文章
专栏主页
目录