业务爸爸需求: 写一个脚本用于向 Consul 注册或注销服务。
(资料图片)
Consul API 实现服务的注册和注销功能
拿到这个需求,我第一时间想到是用 curl 调用 Consul API 实现服务的注册和注销功能。 如下:
#!/bin/bashCONSUL_TOKEN="<your_token_here>"CONSUL_URL="http://localhost:8500"function register_service { curl \ --request PUT \ --header "Content-Type: application/json" \ --header "X-Consul-Token: ${CONSUL_TOKEN}" \ --data "@- ${CONSUL_URL}/v1/agent/service/register" <<EOF{ "ID": "${1}", "Name": "${2}", "Address": "${3}", "Port": ${4}}EOF}function deregister_service { curl \ --request PUT \ --header "X-Consul-Token: ${CONSUL_TOKEN}" \ "${CONSUL_URL}/v1/agent/service/deregister/${1}"}# example usageregister_service "my-service" "My Service" "localhost" 8080deregister_service "my-service"
在这个实现中,我们将认证token存储在CONSUL_TOKEN变量中,并在curl请求中使用--header "X-Consul-Token: ${CONSUL_TOKEN}"来添加它。
这个是可以实现业务爸爸的需求, 但是,这种实现有以下几个问题:
1. 不能批量添加相同的类型的指标。
2. 唯一ID需要手动维护。
3. 没有配置文件留底,虽然三节点的consul集群很小概率同时出问题, 但是有留底还是一个很好习惯。
基于这个几个点, 写入下面实现脚本。
register 和 deregister实现
#!/bin/bash# author 小毛驴# SHELL_DIR=$(cd $(dirname $0);pwd)BACKUP_DIR=${SHELL_DIR}"/consulbackup"SOURCEFILE=${SHELL_DIR}"/origin.json"LOGFILE=${SHELL_DIR}"/add.log"BASESVCRIR=/data/consul/config/TOKENFILE=/data/consul/consul_token.yaml OPTION=${OPTION:="1"}ENV=${ENV:="prod"}PROJECT=${PROJECT:="fb"}MODULE=${MODULE:="api"}SERVICENAME=${SERVICENAME:="node-exporter"}NAME=${NAME:="core"}TAG=${TAG:="node-exporter"}IPADDRS=""IPADDR=""PORT=${PORT:="9520"}LEGAL_IP="^([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"if [ ! -e "${BACKUP_DIR}" ];then mkdir -p ${BACKUP_DIR}fifunction usage(){ echo -e "\nUsage: $0 <option> <value>" echo -e "\n option:" echo -e "\n -o,--option option name, default 1:add , 2:delete" echo -e "\n -e,--env env name, default prod" echo -e "\n -p,--project project name, default fb" echo -e "\n -m,--module module name, default api" echo -e "\n -n,--name api name, default core" echo -e "\n -s,--svcname serviceName name, default node-exporter" echo -e "\n -t,--tag tag name, default node-exporter" echo -e "\n -a,--address ip address, eg 1.1.1.1|2.2.2.2 default '' [Require]" echo -e "\n -i,--interface interface num default 9520" echo -e "\n -h,--help help"}function checkIp(){ #正则表达式检验 ip 地址 [[ $1 =~ $LEGAL_IP ]] if [ $? -gt 0 ]; then echo "$1 is an error ip fromat" exit 10 fi}function svcDeregister() { if [ ! -e "$1" ];then echo "$1 not exit, please check!" else /bin/consul services deregister -token-file=${TOKENFILE} $1 fi}function svcRegister() { if [ ! -e "$1" ];then echo "$1 not exit, please check!" else /bin/consul services register -token-file=${TOKENFILE} $1 fi}function genJson() {cat > "${SERVICENAME}-${ENV}-${PROJECT}-${MODULE}-${NAME}-${IPADDR}.json" <<EOF{ "service": { "id": "${SERVICENAME}-${ENV}-${PROJECT}-${MODULE}-${NAME}-${IPADDR}", "name": "${SERVICENAME}", "tags": [ "${TAG}" ], "address": "${IPADDR}", "port": ${PORT}, "meta": { "name": "${NAME}-${IPADDR}", "module": "${MODULE}", "project": "${PROJECT}", "env": "${ENV}" }, "check": { "http": "http://${IPADDR}:${PORT}/metrics", "interval": "10s" }, "weights": { "passing": 10, "warning": 1 } }}EOF}function removeJson() { mv "${SERVICENAME}-${ENV}-${PROJECT}-${MODULE}-${NAME}-${IPADDR}.json" ${BACKUP_DIR}}function main() { if (($# == 0));then usage exit fi cd ${SHELL_DIR} while [ -n "$1" ];do case $1 in -o|--option ) OPTION=$2 shift ;; -e|--env ) ENV=$2 shift ;; -p|--project ) PROJECT=$2 shift ;; -m|--module ) MODULE=$2 shift ;; -n|--name ) NAME=$2 shift ;; -s|--svcname ) SERVICENAME=$2 shift ;; -t|--tag ) TAG=$2 shift ;; -a|--address ) IPADDRS=$2 shift ;; -i|--interface ) PORT=$2 shift ;; -h|--help ) usage exit ;; *) echo -e "\n$1 unknow an option" usage exit esac shift done if [ "${IPADDRS}"x == ""x ];then echo -e "\n-a|--address option is Require" usage exit fi SVCRIR="${BASESVCRIR}/${SERVICENAME}" if [ ! -e "${SVCRIR}" ];then mkdir -p ${SVCRIR} fi cd ${SVCRIR} hosts=($(echo ${IPADDRS} | sed 's/|/ /g')) for(( i=0;i<${#hosts[@]};i++)) do echo ${hosts[$i]} checkIp ${hosts[$i]} IPADDR="${hosts[$i]}" if [[ "${OPTION}"x == "1"x ]]; then genJson #statements svcRegister "${SERVICENAME}-${ENV}-${PROJECT}-${MODULE}-${NAME}-${IPADDR}.json" fi if [[ "${OPTION}"x == "2"x ]]; then #statements svcDeregister "${SERVICENAME}-${ENV}-${PROJECT}-${MODULE}-${NAME}-${IPADDR}.json" removeJson fi done }main $@
这个脚本首先定义了BACKUP_DIR,BASESVCRIR 和TOKENFILE 等路径。
用法
./register-service.sh [OPTIONS]
参数-h, --help: 显示帮助信息并退出。-o, -option: 1 register ; 2 deregister-e,--env 环境标识, default prod-p,--project 项目名字, default fb-m,--module 业务模块名, default api-n,--name 模块下面的应用名, default core-s,--svcname service 名字, default node-exporter-t,--tag tag 名字, default node-exporter-a,--address 需要注册到该服务的地址,多个以“|”分开,, eg 1.1.1.1|2.2.2.2 default '' [Require],必须提供-i,--interface 需要注册的端口 9520
./register-service.sh -o 1 -e prod -p fb -m ops -n consul-ops -s consul_exporter-t consul_exporter -a "10.2.0.6|10.2.0.10|10.2.0.41" -i 9107