mirror of https://github.com/lework/script
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
9.5 KiB
300 lines
9.5 KiB
#!/usr/bin/env bash |
|
################################################################### |
|
#Script Name : check-container-ip.sh |
|
#Description : Detect container ip addresses and dynamically update nginx upstream configuration |
|
#Create Date : 2021-06-25 |
|
#Author : lework |
|
#Email : lework@yeah.net |
|
################################################################### |
|
|
|
|
|
[[ -n $DEBUG ]] && set -x |
|
set -o errtrace # Make sure any error trap is inherited |
|
set -o nounset # Disallow expansion of unset variables |
|
set -o pipefail # Use last non-zero exit code in a pipeline |
|
|
|
|
|
###################################################################################################### |
|
# environment configuration |
|
###################################################################################################### |
|
|
|
RETRIES="${RETRIES:-9223372036854775807}" |
|
WAIT="${WAIT:-5}" |
|
|
|
CONTAINER_NAME="${CONTAINER_NAME:-}" |
|
CONFIG_FILE="${CONFIG_FILE:-}" |
|
CONFIG_FILE_NAME="${CONFIG_FILE_NAME:-}" |
|
UPSTREAM_NAME="${UPSTREAM_NAME:-}" |
|
SERVICE_PORT="${SERVICE_PORT:-}" |
|
CONTAINER_IP="${CONTAINER_IP:-}" |
|
CHECK_IP="${CHECK_IP:-}" |
|
NGINX_STATUS=0 # 为1时reload nginx |
|
NOTICE_TYPE="${NOTICE_TYPE:-feishu}" |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE:-}" |
|
NOTICE_TOKEN="${NOTICE_TOKEN:-}" |
|
|
|
TMP_DIR="$(rm -rf /tmp/check-container-ip* && mktemp -d -t check-container-ip.XXXXXXXXXX)" |
|
TMP_CONFIG_FILE="${TMP_DIR}/${CONFIG_FILE_NAME}_$(date +%s)_temp.conf" |
|
|
|
NGINX_BACKUP_PATH="${NGINX_BACKUP_PATH:-/tmp}" |
|
|
|
trap trap::info 1 2 3 15 EXIT |
|
|
|
###################################################################################################### |
|
# function |
|
###################################################################################################### |
|
|
|
function trap::info() { |
|
# 信号处理 |
|
|
|
[ ${n:-0} -gt 0 ] && log::info "[stop]" "check total: ${n}" |
|
|
|
trap '' EXIT |
|
exit |
|
} |
|
|
|
|
|
function log::error() { |
|
# 错误日志 |
|
|
|
printf "[%s]: \033[31mERROR: \033[0m%s\n" "$(date +'%Y-%m-%dT%H:%M:%S.%N%z')" "$*" |
|
} |
|
|
|
|
|
function log::info() { |
|
# 基础日志 |
|
|
|
printf "[%s]: \033[32mINFO: \033[0m%s\n" "$(date +'%Y-%m-%dT%H:%M:%S.%N%z')" "$*" |
|
} |
|
|
|
|
|
function log::warning() { |
|
# 警告日志 |
|
|
|
printf "[%s]: \033[33mWARNING: \033[0m%s\n" "$(date +'%Y-%m-%dT%H:%M:%S.%N%z')" "$*" |
|
} |
|
|
|
|
|
function container::get_ip() { |
|
# 获取容器 ip地址 |
|
|
|
log::info "[container]" "Get container ip address." |
|
container_id=$(docker ps -a --no-trunc --filter=status=running --format "table {{.ID}}\t{{.Names}}" | awk "/${CONTAINER_NAME}/{print \$1}") |
|
CONTAINER_IP=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${container_id} 2>/dev/null | tr '\n' ' ' ) |
|
if [[ "$?" != "0" || "${CONTAINER_IP}" == "" ]]; then |
|
log::error "[container]" "Get container ip address error." |
|
exit 1 |
|
fi |
|
|
|
log::info "[container]" "IP: ${CONTAINER_IP}" |
|
} |
|
|
|
function container::check_ip() { |
|
# 检测容器ip地址 |
|
|
|
log::info "[container]" "Check container service status." |
|
CHECK_IP="" |
|
for ip in ${CONTAINER_IP}; do |
|
curl -s --output /dev/null "http://${ip}:${SERVICE_PORT}" && CHECK_IP="${CHECK_IP} ${ip}" |
|
done |
|
log::info "[container]" "Check success: ${CHECK_IP}" |
|
} |
|
|
|
function nginx::get_upstream_ip() { |
|
# 获取 nginx upstream ip地址 |
|
|
|
log::info "[nginx]" "Get nginx upstream ${UPSTREAM_NAME} host." |
|
upstream_ip=$(awk '-F *|:' " |
|
/upstream ${UPSTREAM_NAME}/ { |
|
app = 1 |
|
next |
|
} |
|
/server/ { |
|
if (app) print \$3 |
|
} |
|
/}/ { |
|
if (app) exit |
|
} |
|
" "${CONFIG_FILE}" | tr '\n' ' ') |
|
log::info "[nginx]" "Upstream host: ${upstream_ip}" |
|
} |
|
|
|
function nginx::config() { |
|
# 配置 nginx |
|
|
|
log::info "[nginx]" "Config nginx upstream ${UPSTREAM_NAME} host." |
|
|
|
cp "${CONFIG_FILE}" "${TMP_CONFIG_FILE}" |
|
for ip in ${CHECK_IP}; do |
|
if ! grep "${ip}" "${TMP_CONFIG_FILE}" >/dev/null 2>&1; then |
|
sed -i "/upstream ${UPSTREAM_NAME} {/a\ server ${ip}:${SERVICE_PORT};" "${TMP_CONFIG_FILE}" && NGINX_STATUS=1 |
|
log::info "[nginx]" "IP: ${ip} add to upstream hosts." |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE}**Add**: ${ip} add to upstream hosts.\n" |
|
fi |
|
done |
|
|
|
for ip in ${upstream_ip}; do |
|
if [[ "$CHECK_IP" == *${ip}* ]]; then |
|
log::info "[nginx]" "IP: ${ip} ip already exists on the upstream host." |
|
else |
|
log::info "[nginx]" "IP: ${ip} delete from upstream host." |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE}**Del**: ${ip} delete from upstream host.\n" |
|
sed -i "/server ${ip:-11111111111}:${SERVICE_PORT}/d" "${TMP_CONFIG_FILE}" && NGINX_STATUS=1 |
|
fi |
|
done |
|
|
|
if [[ $NGINX_STATUS == 1 ]]; then |
|
log::info "[nginx]" "Backup nginx config to ${NGINX_BACKUP_PATH}/${CONFIG_FILE_NAME}-$(date +%s)" |
|
cp -f "$CONFIG_FILE" "${NGINX_BACKUP_PATH}/${CONFIG_FILE_NAME}-$(date +%s)" |
|
log::info "[nginx]" "Apply nginx config file." |
|
mv -f "${TMP_CONFIG_FILE}" "$CONFIG_FILE" |
|
fi |
|
} |
|
|
|
|
|
function nginx::reload() { |
|
# 重载 nginx |
|
|
|
if [[ $NGINX_STATUS == 1 ]]; then |
|
log::info "[nginx]" "Reload nginx." |
|
local level=red |
|
if nginx -t >/dev/null 2>&1; then |
|
if nginx -s reload >/dev/null 2>&1; then |
|
log::info "[nginx]" "Reload nginx success." |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE}**Reload**: nginx success.\n" |
|
level=green |
|
else |
|
log::error "[nginx]" "Reload nginx error." |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE}**Reload**: nginx error.\n" |
|
fi |
|
else |
|
log::error "[nginx]" "test nginx config error." |
|
NOTICE_MESSAGE="${NOTICE_MESSAGE}**Test**: nginx config error.\n" |
|
exit 1 |
|
fi |
|
notice "$level" "${NOTICE_MESSAGE}" |
|
fi |
|
} |
|
|
|
function notice() { |
|
# 通知 |
|
|
|
log::info "[notice]" "select ${NOTICE_TYPE}" |
|
if [ -z $NOTICE_TOKEN ];then |
|
log::warning "[notice]" "please set NOTICE_TOKEN" |
|
return |
|
fi |
|
notice::${NOTICE_TYPE} $@ |
|
} |
|
|
|
function notice::feishu() { |
|
# 飞书通知 |
|
|
|
local level="${1:-green}" |
|
local message="${@:2}" |
|
local now_date="$(date +'%Y-%m-%d %T')" |
|
local title="[Upstream] check container ip" |
|
local host="$(ip a | grep glo | awk '{print $2}' | head -1 | cut -f1 -d/)" |
|
|
|
local template="{\"msg_type\":\"interactive\",\"card\":{\"config\":{\"wide_screen_mode\":true,\"enable_forward\":true},\"header\":{\"title\":{\"content\":\"$title\",\"tag\":\"plain_text\"},\"template\":\"${level}\"},\"elements\":[{\"tag\":\"div\",\"text\":{\"content\":\"**发生时间:**\",\"tag\":\"lark_md\"},\"fields\":[{\"is_short\":false,\"text\":{\"tag\":\"lark_md\",\"content\":\"${now_date}\"}}]},{\"tag\":\"div\",\"text\":{\"content\":\"**节点:**\",\"tag\":\"lark_md\"},\"fields\":[{\"is_short\":false,\"text\":{\"tag\":\"lark_md\",\"content\":\"${host}\"}}]},{\"tag\":\"div\",\"text\":{\"content\":\"**详细信息:**\",\"tag\":\"lark_md\"},\"fields\":[{\"is_short\":false,\"text\":{\"tag\":\"lark_md\",\"content\":\"${message}\"}}]},{\"tag\":\"hr\"},{\"tag\":\"note\",\"elements\":[{\"tag\":\"plain_text\",\"content\":\"by lework\"}]}]}}" |
|
|
|
if curl -s -X POST -H "Content-Type: application/json" -d "${template}" "https://open.feishu.cn/open-apis/bot/v2/hook/${NOTICE_TOKEN}" | grep success >/dev/null 2>&1; then |
|
log::info "[notice]" "send feishu success." |
|
else |
|
log::error "[notice]" "send feishu error." |
|
fi |
|
} |
|
|
|
function check::start() { |
|
# 检测流程 |
|
|
|
echo |
|
log::info "[check]" "Start inspection." |
|
|
|
container::get_ip |
|
container::check_ip |
|
nginx::get_upstream_ip |
|
|
|
nginx::config |
|
nginx::reload |
|
|
|
NGINX_STATUS=0 |
|
NOTICE_MESSAGE="" |
|
} |
|
|
|
function help::usage { |
|
# 使用帮助 |
|
|
|
cat << EOF |
|
|
|
Detect container ip addresses and dynamically update nginx upstream configuration. |
|
|
|
Usage: |
|
$(basename "$0") [options] |
|
|
|
Options: |
|
--container-name Docker container name |
|
--config-file Nginx conf path |
|
--upstream-name Nginx upstream name |
|
--service-port Service port |
|
--retries Retries number, default:${RETRIES} |
|
--wait Retries wait time, default:${WAIT} |
|
-h,--help View help |
|
|
|
Example: |
|
$0 --container-name api-test \\ |
|
--config-file /etc/nginx/conf.d/api.conf \\ |
|
--upstream-name api \\ |
|
--service-port 8000 \\ |
|
--retries 20 \\ |
|
--wait 5 |
|
|
|
EOF |
|
exit 1 |
|
} |
|
|
|
|
|
|
|
###################################################################################################### |
|
# main |
|
###################################################################################################### |
|
|
|
[ "$#" == "0" ] && help::usage |
|
|
|
while [ "${1:-}" != "" ]; do |
|
case $1 in |
|
--container-name ) shift |
|
CONTAINER_NAME=${1:-$CONTAINER_NAME} |
|
;; |
|
--config-file ) shift |
|
CONFIG_FILE=${1:-$CONFIG_FILE} |
|
CONFIG_FILE_NAME=$(basename ${CONFIG_FILE}) |
|
;; |
|
--upstream-name ) shift |
|
UPSTREAM_NAME=${1:-$UPSTREAM_NAME} |
|
;; |
|
--service-port ) shift |
|
SERVICE_PORT=${1:-$SERVICE_PORT} |
|
;; |
|
--retries ) shift |
|
RETRIES=${1:-$RETRIES} |
|
;; |
|
--wait ) shift |
|
WAIT=${1:-$WAIT} |
|
;; |
|
-h | --help ) help::usage |
|
;; |
|
* ) help::usage |
|
exit 1 |
|
esac |
|
shift |
|
done |
|
|
|
n=0 |
|
while [[ $n -lt ${RETRIES} ]] |
|
do |
|
check::start |
|
sleep ${WAIT} |
|
let n++ |
|
done |
|
|
|
|