创建自动化部署脚本
在这一步,你将创建一个自动化脚本,演示如何一致且重复地部署 RHEL 容器。该脚本的作用与使用 Kickstart 文件进行 VM 自动化相同,但适用于容器化的 RHEL 部署。该脚本将处理镜像构建、容器部署和基本的健康检查。
首先,确保你在你的工程目录中:
cd ~/project
创建一个部署自动化脚本,该脚本模仿你使用 Kickstart 和 virt-install 实现的自动化功能:
nano deploy-rhel-container.sh
添加以下内容以创建一个全面的部署脚本:
#!/bin/bash
## RHEL 容器自动化部署脚本
## 该脚本演示了基于容器的 RHEL 部署自动化
## 类似于 VM 的 Kickstart 自动化,但适用于容器
set -e ## 遇到任何错误时退出
## 配置变量
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"
## 输出的颜色代码
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## 无颜色
## 打印彩色输出的函数
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
## 检查 Docker 是否正在运行的函数
check_docker() {
print_status "正在检查 Docker 的可用性..."
if ! docker info > /dev/null 2>&1; then
print_error "Docker 未运行或不可访问"
exit 1
fi
print_success "Docker 可用"
}
## 构建镜像的函数
build_image() {
print_status "正在构建 RHEL 容器镜像..."
if [ ! -f "$DOCKERFILE" ]; then
print_error "未找到 Dockerfile '$DOCKERFILE'"
exit 1
fi
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
print_success "镜像 '${IMAGE_NAME}:${IMAGE_TAG}' 构建成功"
}
## 停止并删除现有容器的函数
cleanup_existing() {
print_status "正在检查现有容器..."
if docker ps -a | grep -q "$CONTAINER_NAME"; then
print_warning "正在停止并删除现有容器 '$CONTAINER_NAME'"
docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
fi
}
## 部署容器的函数
deploy_container() {
print_status "正在部署 RHEL 容器..."
docker run -d \
--name "$CONTAINER_NAME" \
-p "${HOST_PORT}:${CONTAINER_PORT}" \
--restart unless-stopped \
"${IMAGE_NAME}:${IMAGE_TAG}"
print_success "容器 '$CONTAINER_NAME' 部署成功"
}
## 验证部署的函数
verify_deployment() {
print_status "正在验证容器部署..."
## 等待容器启动
sleep 5
## 检查容器是否正在运行
if ! docker ps | grep -q "$CONTAINER_NAME"; then
print_error "容器未运行"
docker logs "$CONTAINER_NAME"
exit 1
fi
## 检查 Web 服务是否响应
print_status "正在测试 Web 服务..."
for i in {1..10}; do
if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
print_success "Web 服务正在响应"
break
fi
if [ $i -eq 10 ]; then
print_error "Web 服务在 10 次尝试后未响应"
exit 1
fi
sleep 2
done
}
## 显示部署信息的函数
show_deployment_info() {
print_success "=== RHEL 容器部署完成 ==="
echo "容器名称:$CONTAINER_NAME"
echo "镜像:${IMAGE_NAME}:${IMAGE_TAG}"
echo "端口映射:${HOST_PORT}:${CONTAINER_PORT}"
echo "访问 URL:http://localhost:${HOST_PORT}"
echo ""
print_status "容器状态:"
docker ps | grep "$CONTAINER_NAME"
echo ""
print_status "示例内容:"
curl -s "http://localhost:${HOST_PORT}" | head -2
}
## 主部署流程
main() {
echo "=== RHEL 容器自动化部署 ==="
echo "该脚本自动化 RHEL 容器部署"
echo "类似于传统安装的 Kickstart 自动化"
echo ""
check_docker
build_image
cleanup_existing
deploy_container
verify_deployment
show_deployment_info
print_success "自动化 RHEL 容器部署已成功完成!"
}
## 处理脚本参数
case "${1:-deploy}" in
"deploy" | "")
main
;;
"cleanup")
print_status "正在清理部署..."
cleanup_existing
docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
print_success "清理完成"
;;
"status")
docker ps | grep "$CONTAINER_NAME" || print_warning "容器未运行"
;;
*)
echo "用法:$0 [deploy|cleanup|status]"
echo " deploy - 构建并部署 RHEL 容器(默认)"
echo " cleanup - 停止容器并删除镜像"
echo " status - 显示容器状态"
exit 1
;;
esac
保存文件并退出 nano (Ctrl+X,然后 Y,然后 Enter)。
了解部署脚本结构
在运行脚本之前,让我们了解一下这个自动化脚本的工作原理。本节提供了对每个组件的详细说明,使初学者更容易理解 shell 脚本和容器自动化概念。
脚本标头和错误处理
#!/bin/bash
set -e ## 遇到任何错误时退出
#!/bin/bash:这被称为“shebang”——它告诉系统使用 Bash shell 来执行此脚本
set -e:如果任何命令失败,这将使脚本立即退出,确保脚本在第一个错误处停止,而不是继续使用可能损坏的状态
配置变量
## 配置变量
IMAGE_NAME="rhel9-automated"
IMAGE_TAG="latest"
CONTAINER_NAME="rhel9-production"
HOST_PORT="8080"
CONTAINER_PORT="8080"
DOCKERFILE="rhel9-automated.dockerfile"
这些变量定义了我们部署的所有关键参数。通过将它们放在顶部,我们可以轻松修改部署配置,而无需更改脚本逻辑。这类似于 Kickstart 文件如何使用配置参数。
用户友好的输出系统
## 输出的颜色代码
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' ## 无颜色
## 打印彩色输出的函数
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
这创建了一个具有彩色输出的专业日志记录系统:
\033[0;31m:用于颜色的 ANSI 转义码(31 = 红色,32 = 绿色等)
echo -e:-e 标志启用对颜色使用反斜杠转义的解释
$1:指的是传递给函数的第一个参数
核心部署功能
1. Docker 环境检查
check_docker() {
print_status "正在检查 Docker 的可用性..."
if ! docker info > /dev/null 2>&1; then
print_error "Docker 未运行或不可访问"
exit 1
fi
print_success "Docker 可用"
}
docker info > /dev/null 2>&1:运行 docker info 并将输出 (>) 和错误 (2>&1) 重定向到 /dev/null(丢弃它们)
!:否定结果 - 如果 docker info 失败(返回非零),则条件变为真
- 这相当于检查传统 VM 部署中虚拟化是否可用
2. 镜像构建函数
build_image() {
print_status "正在构建 RHEL 容器镜像..."
if [ ! -f "$DOCKERFILE" ]; then
print_error "未找到 Dockerfile '$DOCKERFILE'"
exit 1
fi
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$DOCKERFILE" .
print_success "镜像 '${IMAGE_NAME}:${IMAGE_TAG}' 构建成功"
}
[ ! -f "$DOCKERFILE" ]:测试 Dockerfile 是否不存在 (! 否定,-f 测试文件是否存在)
docker build -t:使用标签(名称:版本)创建容器镜像
- 这取代了来自 ISO 介质的传统安装过程
3. 清理函数
cleanup_existing() {
print_status "正在检查现有容器..."
if docker ps -a | grep -q "$CONTAINER_NAME"; then
print_warning "正在停止并删除现有容器 '$CONTAINER_NAME'"
docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
fi
}
docker ps -a | grep -q:列出所有容器并安静地搜索我们的容器名称
|| true:确保命令始终成功(返回 0),即使容器不存在
- 这可以防止与现有部署发生冲突
4. 容器部署
deploy_container() {
print_status "正在部署 RHEL 容器..."
docker run -d \
--name "$CONTAINER_NAME" \
-p "${HOST_PORT}:${CONTAINER_PORT}" \
--restart unless-stopped \
"${IMAGE_NAME}:${IMAGE_TAG}"
print_success "容器 '$CONTAINER_NAME' 部署成功"
}
-d:在分离模式下运行容器(后台)
-p "${HOST_PORT}:${CONTAINER_PORT}":将主机端口映射到容器端口
--restart unless-stopped:如果容器停止,则自动重启容器(手动停止除外)
\: 多行命令的行延续字符
5. 健康验证
verify_deployment() {
print_status "正在验证容器部署..."
## 等待容器启动
sleep 5
## 检查容器是否正在运行
if ! docker ps | grep -q "$CONTAINER_NAME"; then
print_error "容器未运行"
docker logs "$CONTAINER_NAME"
exit 1
fi
## 检查 Web 服务是否响应
print_status "正在测试 Web 服务..."
for i in {1..10}; do
if curl -s "http://localhost:${HOST_PORT}" > /dev/null; then
print_success "Web 服务正在响应"
break
fi
if [ $i -eq 10 ]; then
print_error "Web 服务在 10 次尝试后未响应"
exit 1
fi
sleep 2
done
}
{1..10}:Bash 大括号扩展 - 创建序列 1、2、3... 10
curl -s:静默模式 HTTP 请求
break:当服务响应时,提前退出循环
- 这实现了具有超时的重试机制
命令行界面
case "${1:-deploy}" in
"deploy" | "")
main
;;
"cleanup")
print_status "正在清理部署..."
cleanup_existing
docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2> /dev/null || true
print_success "清理完成"
;;
"status")
docker ps | grep "$CONTAINER_NAME" || print_warning "容器未运行"
;;
*)
echo "用法:$0 [deploy|cleanup|status]"
exit 1
;;
esac
${1:-deploy}:参数扩展 - 使用 $1(第一个参数)或 "deploy" 作为默认值
case 语句:类似于其他语言中的 switch/case
;;:终止每个 case 分支
$0:指的是脚本名称本身
这创建了一个多功能脚本,可用于多种操作,类似于系统管理员如何使用不同的工具进行部署、维护和监控。
使脚本可执行:
chmod +x deploy-rhel-container.sh
现在运行自动化部署脚本以查看完整的自动化过程:
./deploy-rhel-container.sh
你应该看到显示完整部署过程的输出:
=== RHEL 容器自动化部署 ===
该脚本自动化 RHEL 容器部署
类似于传统安装的 Kickstart 自动化
[INFO] 正在检查 Docker 的可用性...
[SUCCESS] Docker 可用
[INFO] 正在构建 RHEL 容器镜像...
[SUCCESS] 镜像 'rhel9-automated:latest' 构建成功
[INFO] 正在检查现有容器...
[INFO] 正在部署 RHEL 容器...
[SUCCESS] 容器 'rhel9-production' 部署成功
[INFO] 正在验证容器部署...
[INFO] 正在测试 Web 服务...
[SUCCESS] Web 服务正在响应
[SUCCESS] === RHEL 容器部署完成 ===
容器名称:rhel9-production
镜像:rhel9-automated:latest
端口映射:8080:8080
访问 URL:http://localhost:8080
测试不同的脚本选项:
./deploy-rhel-container.sh status
脚本执行演练
当你运行脚本时,它会自动执行以下序列:
1. 环境验证阶段
脚本首先检查 Docker 是否可用且可访问。这至关重要,因为容器部署需要一个工作的 Docker 环境,类似于 VM 部署需要一个工作的管理程序。
2. 镜像构建阶段
脚本从你的 Dockerfile 构建一个新的容器镜像。此过程:
- 读取
rhel9-automated.dockerfile
- 如果尚未存在,则下载基本 UBI9 镜像
- 执行 Dockerfile 中的每个指令
- 创建一个标记为
rhel9-automated:latest 的新镜像
3. 清理阶段
在部署之前,脚本会检查并删除任何具有相同名称的现有容器。这确保了干净的部署,没有命名冲突。
4. 部署阶段
脚本使用以下方式创建并启动新容器:
- 分离模式:容器在后台运行
- 端口映射:主机端口 8080 映射到容器端口 8080
- 重启策略:如果容器意外停止,则自动重启容器
- 命名容器:易于识别和管理
5. 验证阶段
脚本执行健康检查以确保成功部署:
- 容器状态检查:验证容器是否正在运行
- 服务可用性检查:测试 HTTP 服务响应
- 重试机制:尝试最多 10 次,间隔 2 秒
- 自动故障检测:如果验证失败,则退出并显示错误
6. 信息显示阶段
最后,脚本显示全面的部署信息,包括容器详细信息、访问 URL 和示例内容。
实际用法示例
你可以通过多种方式使用此脚本:
正常部署:
./deploy-rhel-container.sh
## 或显式地
./deploy-rhel-container.sh deploy
检查部署状态:
./deploy-rhel-container.sh status
清理资源:
./deploy-rhel-container.sh cleanup
查看脚本帮助:
./deploy-rhel-container.sh help
优于传统方法的优势
与传统的 Kickstart + VM 部署相比,这种自动化方法具有几个优势:
- 速度:容器启动通常比 VM 启动快 10-100 倍
- 资源效率:容器共享主机内核,使用更少的内存和 CPU
- 一致性:相同的容器在不同的环境中运行相同
- 可扩展性:易于创建多个实例或水平扩展
- 可移植性:可以在任何安装了 Docker 的系统上运行
- 版本控制:容器镜像可以进行版本控制并存储在注册表中
此自动化脚本演示了基于现代容器的 RHEL 部署如何实现与基于传统 Kickstart 的 VM 安装相同级别的自动化和一致性,但具有容器化的额外好处,例如更快的部署、更好的资源利用率以及在现代云环境中更轻松的扩展。