注解:一键安装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 curl 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版本列表,请检查网络连接"
fi
# 显示最近的15个版本
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
warning "您输入的版本 '$tgz' 不在列表中,可能不存在或拼写错误"
read -ep "是否继续安装此版本? (y/n) [n]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
rm -f $VERSIONS_FILE
error "已取消安装,请重新运行脚本并选择正确的版本"
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 -xf $tgz -C ./; then
error "Docker二进制包解压失败"
fi
# 复制文件到指定位置
info "正在安装Docker二进制文件..."
chown root:root docker/*
\cp -rp 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文件
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
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 Compose
install_docker_compose() {
info "正在获取可用的 Docker Compose 版本列表..."
# 获取 GitHub release 版本列表
COMPOSE_VERSIONS_FILE=$(mktemp)
if ! curl -s https://api.github.com/repos/docker/compose/releases \
| grep '"tag_name"' \
| grep -o 'v[0-9]*\.[0-9]*\.[0-9]*' \
| sort -Vu > $COMPOSE_VERSIONS_FILE 2>/dev/null; then
warning "无法从 GitHub 获取 Docker Compose 版本列表,将使用默认版本"
fi
# 显示最近 15 个版本
if [ -s $COMPOSE_VERSIONS_FILE ]; then
info "以下是最近的15个可用 Docker Compose 版本:"
tail -n 15 $COMPOSE_VERSIONS_FILE | cat -n
echo ""
fi
read -ep "请输入版本号 (例如 v2.36.0) [默认为最新版本]: " COMPOSE_VERSION
if [ -z "$COMPOSE_VERSION" ]; then
COMPOSE_VERSION=$(tail -n 1 $COMPOSE_VERSIONS_FILE)
if [ -z "$COMPOSE_VERSION" ]; then
# GitHub API 拉取失败时使用兜底版本
COMPOSE_VERSION="v2.36.0"
warning "无法自动获取最新版本,将使用默认版本: $COMPOSE_VERSION"
else
info "未指定版本,将使用最新版本: $COMPOSE_VERSION"
fi
else
# 格式校验:必须以 v 开头
if [[ ! "$COMPOSE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
warning "版本号格式不正确,应类似 v2.36.0,将使用最新版本"
COMPOSE_VERSION=$(tail -n 1 $COMPOSE_VERSIONS_FILE)
[ -z "$COMPOSE_VERSION" ] && COMPOSE_VERSION="v2.36.0"
fi
fi
rm -f $COMPOSE_VERSIONS_FILE
success "已选择 Docker Compose 版本: $COMPOSE_VERSION"
# 根据系统架构映射下载文件名
case "$Arch" in
x86_64) COMPOSE_ARCH="x86_64" ;;
aarch64) COMPOSE_ARCH="aarch64" ;;
armv7l) COMPOSE_ARCH="armv7" ;;
*)
warning "未知架构 $Arch,尝试使用 x86_64"
COMPOSE_ARCH="x86_64"
;;
esac
COMPOSE_BINARY="docker-compose-linux-${COMPOSE_ARCH}"
COMPOSE_URL="https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/${COMPOSE_BINARY}"
COMPOSE_DEST="/usr/local/bin/docker-compose"
info "正在下载 Docker Compose: $COMPOSE_URL"
# 优先尝试 GitHub 直链,失败则尝试国内代理
if ! wget -c --progress=bar:force -O "$COMPOSE_DEST" "$COMPOSE_URL" 2>/dev/null; then
warning "GitHub 直链下载失败,正在尝试国内代理..."
COMPOSE_PROXY_URL="https://ghproxy.com/$COMPOSE_URL"
if ! wget -c --progress=bar:force -O "$COMPOSE_DEST" "$COMPOSE_PROXY_URL" 2>/dev/null; then
rm -f "$COMPOSE_DEST"
error "Docker Compose 下载失败,请检查网络后手动安装"
fi
fi
# 赋予可执行权限
chmod +x "$COMPOSE_DEST"
# 创建插件目录软链接,兼容 docker compose 子命令方式
PLUGIN_DIR="/usr/libexec/docker/cli-plugins"
mkdir -p "$PLUGIN_DIR"
ln -sf "$COMPOSE_DEST" "$PLUGIN_DIR/docker-compose"
# 验证安装结果
if command -v docker-compose &>/dev/null; then
COMPOSE_INSTALLED_VERSION=$(docker-compose version --short 2>/dev/null)
success "Docker Compose 安装成功,版本: $COMPOSE_INSTALLED_VERSION"
success "独立命令路径: $COMPOSE_DEST"
success "插件链接路径: $PLUGIN_DIR/docker-compose"
else
error "Docker Compose 安装后无法找到命令,请手动检查: $COMPOSE_DEST"
fi
}
# 添加当前用户到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() {
COMPOSE_VER=$(docker-compose version --short 2>/dev/null || echo "未知")
echo -e "\n${GREEN}=========================================${NC}"
echo -e "${GREEN} Docker 及 Compose 安装成功!${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 "\n${BLUE}Docker Compose 命令示例 (版本: $COMPOSE_VER):${NC}"
echo -e " ${YELLOW}docker compose up -d${NC} - 启动 Compose 服务 (v2 插件方式)"
echo -e " ${YELLOW}docker compose down${NC} - 停止并移除 Compose 服务"
echo -e " ${YELLOW}docker compose ps${NC} - 查看 Compose 服务状态"
echo -e " ${YELLOW}docker compose logs -f${NC} - 实时查看 Compose 服务日志"
echo -e " ${YELLOW}docker-compose up -d${NC} - 启动 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 Compose
install_docker_compose
# 添加当前用户到docker组
add_user_to_docker_group
# 验证Docker安装
verify_docker
# 显示安装完成信息
show_completion_info
}
# 执行主函数
main "$@"