#!/bin/bash
# vim:sw=4:ts=4:et
<<INFO
AUTHOR:运维@小兵
DATE:2021-01-28
DESCRIBE:1、rpm方式安装/卸载Docker,可以指定数据盘作为Docker的存储盘
SYSTEM:CentOS7/RedHat7
WARNING:
MODIFY:2021-10-21:删除docker组之前先删除docker用户
INFO

set -e

WORKDIR=$(cd `dirname $0`;pwd)
LOG_PATH=${WORKDIR}/docker.log
DOCKER_VERSION="18.09.0"
DOCKER_STORAGE="/data/docker" #使用逻辑卷时,挂载到该路径
VG_NAME="dockervg"
LV_NAME="${VG_NAME}_storage"

#${FUNCNAME[1]代表调用该函数的函数,$LINENO代表当前代码行号
Log(){
local log_level=$1
local log_info=$2
local line=$3
local script_name=$(basename $0)

case ${log_level} in
"INFO")
echo -e "\033[32m$(date "+%Y-%m-%d %T.%N") [INFO]: ${log_info}\033[0m";;
"WARN")
echo -e "\033[33m$(date "+%Y-%m-%d %T.%N") [WARN]: ${log_info}\033[0m";;
"ERROR")
echo -e "\033[31m$(date "+%Y-%m-%d %T.%N") [ERROR ${script_name} ${FUNCNAME[1]}:$line]: ${log_info}\033[0m";;
*)
echo -e "${@}"
;;
esac
}

# 检查当前环境
Check_Env(){
local docker_status=$(systemctl is-active docker)
if [[ ${docker_status} == "active" ]];then
Log WARN "Docker Is Installed" && exit 0
elif which docker &> /dev/null;then
Log WARN "Docker Is Installed" && exit 0
fi
if ! grep '^docker:' /etc/group &> /dev/null;then
groupadd docker
fi
if [[ ! -d ${WORKDIR}/rpm_x86 ]];then
Log ERROR "${WORKDIR}/rpm_x86 Not Found" $LINENO && exit 1
fi
}

# 创建逻辑卷,当作Docker存储路径
Create_Lvm(){
Log INFO "Begin Create LVM....."
local disk_name=$1
local disk_num=$(fdisk -l |grep "${disk_name}" |wc -l)
[[ ${disk_num} -gt 1 ]] && Log ERROR "${disk_name} Is Used,Please Format or Change New Disk" $LINENO && exit 1
if pvs | grep -w ${disk_name};then
Log ERROR "${disk_name} Is Used,Please Format or Change New Disk" $LINENO && exit 1
fi
Log INFO "挂载磁盘为:${disk_name}"
#创建卷组
if ! vgs | grep -w "${VG_NAME}" >/dev/null;then
vgcreate "${VG_NAME}" "${disk_name}"
else
Log ERROR "${VG_NAME} Is Exist" $LINENO && exit 1
fi
#创建逻辑卷
if ! lvs | grep -w "${LV_NAME}" >/dev/null;then
lvcreate -n ${LV_NAME} -l 100%VG ${VG_NAME} -y
mkfs.ext4 /dev/${VG_NAME}/${LV_NAME} >/dev/null
else
Log ERROR "${LV_NAME} Is Exist" $LINENO && exit 1
fi
if lvs | grep -w ${LV_NAME};then
Log INFO "${LV_NAME} Create Success"
else
Log ERROR "${LV_NAME} Create Faild" $LINENO && exit 1
fi
# 挂载逻辑卷
if [[ ! -d ${DOCKER_STORAGE} ]];then
mkdir -p ${DOCKER_STORAGE}
local uuid=$(blkid | grep -w "${VG_NAME}-${LV_NAME}" |awk '{print $2}')
[[ ! -f /etc/fstab.bak ]] && cp /etc/fstab{,.bak}
sed -ri "s#(.*)${DOCKER_STORAGE}(.*)##" /etc/fstab #防止多次写入相同的挂载内容
echo "${uuid} ${DOCKER_STORAGE} ext4 defaults 0 0" >> /etc/fstab
sed -i '/^$/d' /etc/fstab
mount -a
if df -h | grep -w "${DOCKER_STORAGE}$";then
Log INFO "${DOCKER_STORAGE} Mount Success"
else
Log ERROR "${DOCKER_STORAGE} Mount Faild" $LINENO && exit 1
fi
else
Log ERROR "${DOCKER_STORAGE} Is Exist" $LINENO && exit 1
fi
}

# 删除逻辑卷
Remove_Lvm(){
Log INFO "Begin Remove LVM....."
local disk_name=$1
if df -h | grep -w "${DOCKER_STORAGE}$" &> /dev/null;then
umount ${DOCKER_STORAGE}
fi
[[ ! -f /etc/fstab.bak ]] && cp /etc/fstab{,.bak}
sed -ri "s#(.*)${DOCKER_STORAGE}(.*)##" /etc/fstab
sed -i '/^$/d' /etc/fstab
#删除逻辑卷
if lvs | grep -w "${LV_NAME}" >/dev/null;then
lvremove -f /dev/${VG_NAME}/${LV_NAME}
fi
#删除卷组
if vgs | grep -w "${VG_NAME}" >/dev/null;then
vgremove ${VG_NAME}
fi
#删除物理卷
if pvs | grep -w "${disk_name}" >/dev/null;then
pvremove "${disk_name}"
fi
[[ -d ${DOCKER_STORAGE} ]] && rm -rf ${DOCKER_STORAGE}
Log INFO "Remove LVM Success"
}

# 修改Docker存储路径
Modify_Docker_Storage(){
[[ ! -d /etc/docker ]] && mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"graph":"${DOCKER_STORAGE}"
}
EOF
}

Install_Docker(){
Log INFO "Begin Install Docker ${DOCKER_VERSION}....."
local disk_name=$1
Check_Env
[[ -f /etc/sysconfig/docker ]] && mv /etc/sysconfig/docker /etc/sysconfig/docker.bak
if [[ -n ${disk_name} ]];then
Create_Lvm ${disk_name}
Modify_Docker_Storage
fi
cd ${WORKDIR}/rpm_x86 && rpm -ivh *.rpm --force --nodeps
systemctl enable docker
systemctl restart docker
local docker_status=$(systemctl is-active docker)
if [[ ${docker_status} == "active" ]];then
docker -v
Log INFO "Install Docker Success"
else
Log ERROR "Install Docker Faild" $LINENO && exit 1
fi
}

Uninstall_Docker(){
Log INFO "Begin Uninstall Docker......"
local disk_name=$1
local docker_status=$(systemctl is-active docker)
if [[ ${docker_status} == "active" ]];then
docker ps | grep -v 'CONTAINER' | awk '{print $1}' | xargs -i docker stop {}
docker system prune -a -f
systemctl disable docker
systemctl stop docker
else
Log WARN "Docker Is Stop"
fi
yum remove docker-engine docker-engine-selinux -y
if [[ -n ${disk_name} ]];then
Remove_Lvm ${disk_name}
else
[[ -d /var/lib/docker ]] && rm -rf /var/lib/docker
fi
if id docker &> /dev/null;then
userdel -r docker
fi
if grep '^docker:' /etc/group &> /dev/null;then
groupdel docker
fi
[[ -f /etc/sysconfig/docker ]] && rm -f /etc/sysconfig/docker
local docker_status=$(systemctl is-active docker)
if [[ ${docker_status} != "active" ]];then
if ! which docker &> /dev/null;then
Log INFO "Uninstall Docker Success" && exit 0
else
Log ERROR "Uninstall Docker Faild" $LINENO && exit 1
fi
else
Log ERROR "Uninstall Docker Faild" $LINENO && exit 1
fi
}

#帮助信息
Help(){
cat << EOF
Usage:
=======================================================================
optional arguments:
help 提供帮助信息
install 安装docker,存储路径为/var/lib/docker
install /dev/xvde 安装docker,创建逻辑卷,存储路径为:${DOCKER_STORAGE}
uninstal 卸载docker,如果安装时指定了磁盘,卸载也需要指定磁盘
EXAMPLE:
bash install_docker.sh install /dev/xvde
bash install_docker.sh uninstall /dev/xvde
bash install_docker.sh install
bash install_docker.sh uninstall
EOF
}

######################主程序######################
[[ $UID -ne 0 ]] && Log ERROR "Please Use Admin(root) Excute......" $LINENO | tee -a ${LOG_PATH} && exit 1
[[ $# -ne 1 && $# -ne 2 ]] && Help && exit 1

if [[ -n $2 ]];then
if [[ -b $2 ]];then
DISK_NAME=$2
Log INFO "Docker数据盘为:${DISK_NAME}"
else
Log ERROR "$2 Not Is Disk Or Not Found" $LINENO | tee -a ${LOG_PATH} && exit 1
fi
fi

case $1 in
install)
Install_Docker ${DISK_NAME} | tee -a ${LOG_PATH};;
uninstall)
Uninstall_Docker ${DISK_NAME} | tee -a ${LOG_PATH};;
help)
Help;;
*)
Log ERROR "Invalid option:bash `basename $0` help" $LINENO | tee -a ${LOG_PATH} && exit 1
esac