注解:一键安装docker单环境脚本,支持自定义版本(运行此脚本会使docker环境完全清空,请谨慎执行)
#!/bin/bash
# 设置颜色变量
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 恢复默认颜色
Arch=$(arch) # 获取系统类型
# 日志文件
LOG_FILE="/var/log/docker_install_$(date +%Y%m%d%H%M%S).log"
# 记录日志函数
log() {
echo -e "$(date +"%Y-%m-%d %H:%M:%S") $1" | tee -a "$LOG_FILE"
}
# 成功消息
success() {
log "${GREEN}[成功]${NC} $1"
}
# 错误消息
error() {
log "${RED}[错误]${NC} $1"
exit 1
}
# 警告消息
warning() {
log "${YELLOW}[警告]${NC} $1"
}
# 信息消息
info() {
log "${BLUE}[信息]${NC} $1"
}
# 检查是否为root用户运行
check_root() {
if [ "$(id -u)" -ne 0 ]; then
error "请使用root权限运行此脚本"
fi
success "当前以root权限运行"
}
# 确保网络连通
check_network() {
info "正在检查网络连通性..."
# 尝试多个站点以提高可靠性
for site in www.baidu.com www.aliyun.com www.qq.com; do
if ping -c 2 -W 3 $site &>/dev/null; then
success "网络连通性检查通过 (可访问 $site)"
return 0
fi
done
error "外网不通,无法继续安装。请检查您的网络配置后重试。"
}
# 获取系统信息
get_system_info() {
info "正在获取系统信息..."
# 获取系统架构
Arch=$(arch)
success "系统架构: $Arch"
# 获取操作系统版本
if [ -f /etc/os-release ]; then
source /etc/os-release
OS_NAME=$NAME
OS_VERSION=$VERSION_ID
success "操作系统: $OS_NAME $OS_VERSION"
else
warning "无法确定操作系统版本"
fi
# 检查内存
MEM_TOTAL=$(free -m | awk '/^Mem:/{print $2}')
success "系统内存: $MEM_TOTAL MB"
# 检查磁盘空间
DISK_FREE=$(df -h / | awk 'NR==2 {print $4}')
success "根分区可用空间: $DISK_FREE"
# 如果内存小于2GB,给出警告
if [ $MEM_TOTAL -lt 2048 ]; then
warning "系统内存小于2GB,Docker可能无法正常运行某些容器"
fi
}
# 系统环境配置
configure_system() {
info "正在配置系统环境..."
# 修改时区为上海
info "修改时区为Asia/Shanghai..."
if timedatectl set-timezone Asia/Shanghai; then
success "时区已设置为Asia/Shanghai"
else
warning "时区设置失败"
fi
# 修改selinux
info "正在关闭SELinux..."
if [ -f /etc/selinux/config ]; then
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
setenforce 0 &>/dev/null || true
success "SELinux已关闭"
else
warning "未找到SELinux配置文件"
fi
# 关闭防火墙
info "正在关闭防火墙..."
if systemctl stop firewalld &>/dev/null && systemctl disable firewalld &>/dev/null; then
success "防火墙已关闭并禁止开机自启动"
else
warning "防火墙操作失败,可能不存在firewalld服务"
fi
# 开启IP转发
info "正在开启IP转发功能..."
sed -i "/net.ipv4.ip_forward/d" /etc/sysctl.conf
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
if sysctl -p &>/dev/null; then
success "IP转发功能已开启"
else
warning "IP转发设置可能失败"
fi
# 同步时间
info "正在同步系统时间..."
if which ntpdate &>/dev/null; then
ntpdate ntp1.aliyun.com &>/dev/null && success "系统时间已同步" || warning "时间同步失败"
else
info "正在安装ntpdate..."
yum -y install ntp ntpdate &>/dev/null && ntpdate ntp1.aliyun.com &>/dev/null && success "系统时间已同步" || warning "时间同步失败"
fi
}
# 彻底清理现有Docker安装
clean_existing_docker() {
info "正在彻底清理现有Docker安装..."
# 停止所有相关服务
systemctl stop docker.service docker.socket containerd.service &>/dev/null || true
# 卸载现有Docker软件包
yum remove -y docker docker-client docker-client-latest docker-common docker-latest \
docker-latest-logrotate docker-logrotate docker-engine docker-ce docker-ce-cli containerd.io &>/dev/null || true
# 删除相关文件和目录
rm -rf /usr/bin/docker /usr/bin/containerd /etc/docker /usr/lib/systemd/system/docker* /usr/lib/systemd/system/containerd* &>/dev/null || true
# 重新加载systemd配置
systemctl daemon-reload &>/dev/null
systemctl reset-failed &>/dev/null
success "已清理现有Docker安装"
}
# 安装依赖
install_dependencies() {
info "正在安装必要的依赖软件..."
yum -y install wget ntp yum-utils device-mapper-persistent-data lvm2 &>/dev/null
if [ $? -eq 0 ]; then
success "依赖软件安装完成"
else
error "依赖软件安装失败,请检查yum源配置"
fi
}
# 选择Docker版本
select_docker_version() {
info "正在获取可用的Docker版本列表..."
# 创建临时文件存储版本列表
VERSIONS_FILE=$(mktemp)
# 获取版本列表
if ! curl -s https://download.docker.com/linux/static/stable/$Arch/ | grep -o 'docker-[0-9]*\.[0-9]*\.[0-9]*\.tgz' | sort -Vu > $VERSIONS_FILE; then
error "无法获取Docker版本列表,请检查网络连接"
exit 1
fi
# 显示最近的10个版本
info "以下是最近的15个可用Docker版本:"
tail -n 15 $VERSIONS_FILE | cat -n
# 用户选择版本
echo ""
read -ep "请输入完整版本名称(例如 docker-28.0.0.tgz) [默认为最新版本]: " tgz
if [ -z "$tgz" ]; then
# 默认选择最新版本
tgz=$(tail -n 1 $VERSIONS_FILE)
info "未指定版本,将使用最新版本: $tgz"
else
# 验证用户输入的版本是否存在
if ! grep -q "^$tgz$" $VERSIONS_FILE; then
warn "您输入的版本 '$tgz' 不在列表中,可能不存在或拼写错误"
read -ep "是否继续安装此版本? (y/n) [n]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
error "已取消安装,请重新运行脚本并选择正确的版本"
rm -f $VERSIONS_FILE
exit 1
fi
fi
fi
success "已选择Docker版本: $tgz"
rm -f $VERSIONS_FILE
}
# 下载并安装Docker
download_and_install_docker() {
info "正在下载Docker二进制包: $tgz"
# 创建临时目录
TMP_DIR=$(mktemp -d)
cd $TMP_DIR || error "无法创建临时目录"
# 下载Docker二进制包
if ! wget -c --progress=bar:force https://download.docker.com/linux/static/stable/$Arch/$tgz; then
error "Docker二进制包下载失败"
fi
success "Docker二进制包下载完成"
# 解压文件
info "正在解压Docker二进制包..."
if ! tar -zxf $tgz -C ./ ; then
error "Docker二进制包解压失败"
fi
# 复制文件到指定位置
info "正在安装Docker二进制文件..."
chown root:root docker/*
\cp -p docker/* /usr/bin/
# 创建docker用户组
info "正在创建docker用户组..."
groupadd docker &>/dev/null || true
success "docker用户组已创建"
# 清理临时文件
cd - > /dev/null
rm -rf $TMP_DIR
}
# 创建服务文件
create_service_files() {
info "正在创建Docker服务文件..."
# 创建目录
mkdir -p /usr/lib/systemd/system
# 创建docker.socket文件
cat > /usr/lib/systemd/system/docker.socket << 'EOF'
[Unit]
Description=Docker Socket for the API
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
# 创建containerd.service文件
cat > /usr/lib/systemd/system/containerd.service << 'EOF'
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
EOF
# 创建docker.service文件 - 修改为不强制要求containerd.service
cat > /usr/lib/systemd/system/docker.service << 'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service
Wants=network-online.target containerd.service
Requires=docker.socket
[Service]
Type=notify
# 如果没有containerd,则使用内置的
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
EOF
success "Docker服务文件创建完成"
}
# 配置Docker
configure_docker() {
info "正在配置Docker..."
# 创建配置目录
mkdir -p /etc/docker
# 创建daemon.json配置文件
cat > /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
]
}
EOF
success "Docker配置完成"
}
# 启动Docker服务
start_docker() {
info "正在启动Docker服务..."
# 重新加载systemd配置
systemctl daemon-reload
# 启用并启动docker.socket
systemctl enable docker.socket &>/dev/null
systemctl start docker.socket &>/dev/null
# 尝试启动containerd服务
info "正在启动containerd服务..."
systemctl enable containerd &>/dev/null
if ! systemctl start containerd &>/dev/null; then
warning "containerd服务启动失败,将尝试在没有containerd的情况下启动Docker"
else
success "containerd服务启动成功"
fi
# 启用并启动Docker服务
info "正在启动Docker服务..."
systemctl enable docker.service &>/dev/null
# 尝试启动Docker服务
if ! systemctl start docker.service &>/dev/null; then
# 如果启动失败,查看日志
journalctl -xeu docker.service --no-pager | tail -n 20 >> $LOG_FILE
# 修改docker.service文件,移除containerd依赖
info "Docker服务启动失败,尝试修改配置后重新启动..."
sed -i 's/Wants=network-online.target containerd.service/Wants=network-online.target/g' /usr/lib/systemd/system/docker.service
# 重新加载systemd配置
systemctl daemon-reload
# 再次尝试启动
if ! systemctl start docker.service &>/dev/null; then
error "Docker服务启动失败,请检查日志: journalctl -xeu docker.service"
fi
fi
# 检查Docker服务状态
if systemctl is-active docker &>/dev/null; then
success "Docker服务启动成功"
else
error "Docker服务启动失败,请检查日志: journalctl -xeu docker.service"
fi
# 显示Docker版本信息
docker_version=$(docker --version | cut -d ' ' -f 3 | tr -d ',')
success "Docker版本: $docker_version"
}
# 添加当前用户到docker组
add_user_to_docker_group() {
if [ "$SUDO_USER" ]; then
info "正在将用户 $SUDO_USER 添加到docker组..."
usermod -aG docker $SUDO_USER
success "用户 $SUDO_USER 已添加到docker组 (需要重新登录才能生效)"
else
info "如果需要非root用户使用Docker,请运行: sudo usermod -aG docker 用户名"
fi
}
# 验证Docker安装
verify_docker() {
info "正在验证Docker安装..."
# 检查Docker是否正在运行
if ! docker info &>/dev/null; then
warning "Docker验证失败: 无法获取Docker信息"
return
fi
# 显示Docker信息
docker info | grep -E "Containers:|Images:|Server Version:|Storage Driver:|Logging Driver:" | while read line; do
info "$line"
done
# 尝试运行hello-world容器
info "尝试运行hello-world测试容器..."
if docker run --rm hello-world &>/dev/null; then
success "Docker验证成功: hello-world容器运行正常"
else
warning "无法运行hello-world容器,可能需要手动拉取镜像"
fi
}
# 显示安装完成信息
show_completion_info() {
echo -e "\n${GREEN}=========================================${NC}"
echo -e "${GREEN} Docker 安装成功!${NC}"
echo -e "${GREEN}=========================================${NC}"
echo -e "\n${BLUE}Docker 命令示例:${NC}"
echo -e " ${YELLOW}docker info${NC} - 显示Docker系统信息"
echo -e " ${YELLOW}docker ps${NC} - 列出运行中的容器"
echo -e " ${YELLOW}docker images${NC} - 列出本地镜像"
echo -e " ${YELLOW}docker run${NC} - 运行容器"
echo -e " ${YELLOW}docker-compose${NC} - 使用Docker Compose (如已安装)"
echo -e "\n${BLUE}服务管理:${NC}"
echo -e " ${YELLOW}systemctl status docker${NC} - 查看Docker状态"
echo -e " ${YELLOW}systemctl restart docker${NC} - 重启Docker服务"
echo -e "\n${BLUE}日志文件:${NC} ${YELLOW}$LOG_FILE${NC}"
echo -e "\n${GREEN}感谢使用Docker安装脚本!${NC}\n"
}
# 主函数
main() {
echo -e "${BLUE}=========================================${NC}"
echo -e "${BLUE} Docker 安装与配置脚本${NC}"
echo -e "${BLUE}=========================================${NC}"
# 检查root权限
check_root
# 检查网络连通性
check_network
# 获取系统信息
get_system_info
# 配置系统环境
configure_system
# 彻底清理现有Docker安装
clean_existing_docker
# 安装依赖
install_dependencies
# 选择Docker版本
select_docker_version
# 下载并安装Docker
download_and_install_docker
# 创建服务文件
create_service_files
# 配置Docker
configure_docker
# 启动Docker服务
start_docker
# 添加当前用户到docker组
add_user_to_docker_group
# 验证Docker安装
verify_docker
# 显示安装完成信息
show_completion_info
}
# 执行主函数
main "$@"