354 lines
11 KiB
Bash
Executable File
354 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
set -euo pipefail
|
||
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
RED='\033[0;31m'
|
||
NC='\033[0m'
|
||
|
||
log_info() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
log_warn() {
|
||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||
}
|
||
|
||
log_err() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
# 检查 root 权限
|
||
if [ "$EUID" -ne 0 ]; then
|
||
log_err "请使用 root 权限执行此脚本(如: sudo bash $0)"
|
||
exit 1
|
||
fi
|
||
|
||
log_info "=========================================="
|
||
log_info "开始初始化实验环境..."
|
||
log_info "=========================================="
|
||
|
||
# 直接连接终端,保留 yum 原生下载进度条;不要通过 tee 管道转存输出。
|
||
run_yum() {
|
||
local status
|
||
log_info "执行 yum $*(下载速度取决于网络和镜像源)..."
|
||
# 仅启用本地仓库,避免系统中其他已启用的公网仓库参与下载。
|
||
if yum --disablerepo='*' \
|
||
--enablerepo=local-base,local-updates,local-extras,local-qemu-ev,local-openstack-rocky \
|
||
"$@"; then
|
||
log_info "yum 操作完成。"
|
||
else
|
||
status=$?
|
||
log_err "yum 操作失败(退出码 $status),请查看上方错误信息。"
|
||
return "$status"
|
||
fi
|
||
}
|
||
|
||
REPO_DIR="/etc/yum.repos.d"
|
||
BACKUP_DIR="/etc/yum.repos.d.bak"
|
||
|
||
# 首次运行时备份原有软件源
|
||
if [ ! -d "$BACKUP_DIR" ]; then
|
||
log_info "备份原有 yum 软件源..."
|
||
cp -a "$REPO_DIR" "$BACKUP_DIR"
|
||
fi
|
||
|
||
# 配置 CentOS 7.9 基础源
|
||
log_info "配置 CentOS 7.9 本地软件源(192.168.192.205:3080)..."
|
||
|
||
cat > "$REPO_DIR/CentOS-Base.repo" <<'EOF'
|
||
[local-base]
|
||
name=Local - Base
|
||
baseurl=http://192.168.192.205:3080/vault-base/
|
||
gpgcheck=0
|
||
enabled=1
|
||
|
||
[local-updates]
|
||
name=Local - Updates
|
||
baseurl=http://192.168.192.205:3080/vault-updates/
|
||
gpgcheck=0
|
||
enabled=1
|
||
|
||
[local-extras]
|
||
name=Local - Extras
|
||
baseurl=http://192.168.192.205:3080/vault-extras/
|
||
gpgcheck=0
|
||
enabled=1
|
||
EOF
|
||
|
||
# 配置 QEMU EV 源
|
||
cat > "$REPO_DIR/CentOS-QEMU-EV.repo" <<'EOF'
|
||
[local-qemu-ev]
|
||
name=Local - QEMU EV
|
||
baseurl=http://192.168.192.205:3080/vault-centos-qemu-ev/
|
||
gpgcheck=0
|
||
enabled=1
|
||
EOF
|
||
|
||
# 配置 OpenStack Rocky 源
|
||
cat > "$REPO_DIR/CentOS-OpenStack-rocky.repo" <<'EOF'
|
||
[local-openstack-rocky]
|
||
name=Local - OpenStack Rocky
|
||
baseurl=http://192.168.192.205:3080/vault-centos-openstack-rocky/
|
||
gpgcheck=0
|
||
enabled=1
|
||
exclude=sip,PyQt4
|
||
EOF
|
||
|
||
# 删除不再需要的 Ceph 源,避免 yum 读取其元数据
|
||
rm -f "$REPO_DIR/CentOS-Ceph-Luminous.repo"
|
||
|
||
|
||
# 清除旧仓库元数据,保留已下载的软件包缓存
|
||
log_info "刷新软件源元数据..."
|
||
run_yum clean metadata
|
||
|
||
CONTROLLER_IP="192.168.30.129"
|
||
CONTROLLER_HOSTNAME="controller"
|
||
|
||
# 首次修改时备份配置,重复运行不覆盖原始备份。
|
||
backup_config() {
|
||
if [ -f "$1" ] && [ ! -e "$1.env3-2.bak" ]; then
|
||
cp -a "$1" "$1.env3-2.bak"
|
||
fi
|
||
}
|
||
|
||
log_info "关闭防火墙和 SELinux..."
|
||
if systemctl list-unit-files firewalld.service --no-legend | grep -q '^firewalld.service'; then
|
||
systemctl stop firewalld
|
||
systemctl disable firewalld
|
||
fi
|
||
if command -v getenforce > /dev/null 2>&1; then
|
||
if [ "$(getenforce)" = "Enforcing" ]; then
|
||
setenforce 0
|
||
fi
|
||
fi
|
||
if [ -f /etc/selinux/config ]; then
|
||
backup_config /etc/selinux/config
|
||
sed -i '/^[[:space:]]*SELINUX=/d' /etc/selinux/config
|
||
echo 'SELINUX=disabled' >> /etc/selinux/config
|
||
fi
|
||
|
||
log_info "配置主机名和 hosts 解析..."
|
||
hostnamectl set-hostname "$CONTROLLER_HOSTNAME"
|
||
backup_config /etc/hosts
|
||
# 移除旧 controller 映射,保留同一行的其他别名及注释。
|
||
HOSTS_TMP=$(mktemp)
|
||
awk -v host="$CONTROLLER_HOSTNAME" '
|
||
/^[[:space:]]*#/ || NF == 0 { print; next }
|
||
{
|
||
comment = ""
|
||
pos = index($0, "#")
|
||
if (pos) {
|
||
comment = substr($0, pos)
|
||
$0 = substr($0, 1, pos - 1)
|
||
}
|
||
line = $1
|
||
aliases = 0
|
||
for (i = 2; i <= NF; i++) {
|
||
if ($i != host) {
|
||
line = line " " $i
|
||
aliases++
|
||
}
|
||
}
|
||
if (aliases) print line (comment == "" ? "" : " " comment)
|
||
else if (comment != "") print comment
|
||
}
|
||
' /etc/hosts > "$HOSTS_TMP"
|
||
cat "$HOSTS_TMP" > /etc/hosts
|
||
rm -f "$HOSTS_TMP"
|
||
printf '%s %s\n' "$CONTROLLER_IP" "$CONTROLLER_HOSTNAME" >> /etc/hosts
|
||
|
||
log_info "升级系统软件包,合并安装虚拟化、OpenStack 基础服务和 Keystone..."
|
||
run_yum -y upgrade
|
||
run_yum install -y chrony python2-openstackclient \
|
||
mariadb mariadb-server python2-PyMySQL \
|
||
rabbitmq-server memcached python-memcached etcd \
|
||
qemu-kvm libvirt virt-install bridge-utils qemu-img \
|
||
openstack-keystone httpd mod_wsgi
|
||
|
||
# 启动 libvirtd
|
||
log_info "启动 libvirtd 服务..."
|
||
|
||
systemctl enable --now libvirtd > /dev/null
|
||
|
||
# 验证服务状态
|
||
if systemctl is-active --quiet libvirtd; then
|
||
log_info "libvirtd 状态正常。"
|
||
else
|
||
log_err "libvirtd 启动失败!"
|
||
exit 1
|
||
fi
|
||
|
||
|
||
log_info "配置 chrony 时间服务器..."
|
||
backup_config /etc/chrony.conf
|
||
if ! grep -Eq '^[[:space:]]*allow[[:space:]]+all([[:space:]]*(#.*)?)?$' /etc/chrony.conf; then
|
||
printf '\n# 允许所有网段的机器访问同步时间\nallow all\n' >> /etc/chrony.conf
|
||
fi
|
||
systemctl enable chronyd
|
||
systemctl restart chronyd
|
||
|
||
log_info "配置 MariaDB..."
|
||
mkdir -p /etc/my.cnf.d
|
||
backup_config /etc/my.cnf.d/openstack.cnf
|
||
cat > /etc/my.cnf.d/openstack.cnf <<'EOF'
|
||
[mysqld]
|
||
bind-address = 0.0.0.0
|
||
# 默认使用 InnoDB,每个表的数据独立保存成文件。
|
||
default-storage-engine = innodb
|
||
innodb_file_per_table = on
|
||
# 调高最大连接数,并使用 UTF-8 字符集。
|
||
max_connections = 4096
|
||
collation-server = utf8_general_ci
|
||
character-set-server = utf8
|
||
EOF
|
||
systemctl enable mariadb
|
||
systemctl restart mariadb
|
||
|
||
log_info "初始化 MariaDB 安全配置及 root 远程登录权限..."
|
||
# CentOS 7 的 MariaDB 5.5:自动执行 mysql_secure_installation 的等效操作。
|
||
# 使用权限为 600 的临时客户端配置,避免把密码放进进程参数。
|
||
MYSQL_AUTH_FILE=$(mktemp)
|
||
trap 'rm -f "$MYSQL_AUTH_FILE"' EXIT
|
||
chmod 600 "$MYSQL_AUTH_FILE"
|
||
cat > "$MYSQL_AUTH_FILE" <<'EOF'
|
||
[client]
|
||
user=root
|
||
password=123456
|
||
protocol=socket
|
||
EOF
|
||
MYSQL_CMD=(mysql --defaults-extra-file="$MYSQL_AUTH_FILE")
|
||
if ! "${MYSQL_CMD[@]}" -e 'SELECT 1' > /dev/null 2>&1; then
|
||
MYSQL_CMD=(mysql --no-defaults --user=root --protocol=socket)
|
||
if ! "${MYSQL_CMD[@]}" -e 'SELECT 1' > /dev/null 2>&1; then
|
||
log_err "无法使用空密码或预设密码连接 MariaDB root,请检查已有数据库凭据。"
|
||
exit 1
|
||
fi
|
||
fi
|
||
"${MYSQL_CMD[@]}" <<'SQL'
|
||
DELETE FROM mysql.user WHERE User = '';
|
||
DELETE FROM mysql.user
|
||
WHERE User = 'root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
|
||
UPDATE mysql.user SET Password = PASSWORD('123456') WHERE User = 'root';
|
||
DROP DATABASE IF EXISTS test;
|
||
DELETE FROM mysql.db WHERE Db = 'test' OR Db = 'test\_%';
|
||
FLUSH PRIVILEGES;
|
||
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
|
||
FLUSH PRIVILEGES;
|
||
SQL
|
||
log_info "创建 Keystone 数据库并授权..."
|
||
mysql --defaults-extra-file="$MYSQL_AUTH_FILE" <<'SQL'
|
||
CREATE DATABASE IF NOT EXISTS keystone;
|
||
GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'keystone';
|
||
GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'keystone';
|
||
FLUSH PRIVILEGES;
|
||
SQL
|
||
rm -f "$MYSQL_AUTH_FILE"
|
||
trap - EXIT
|
||
|
||
log_info "配置 RabbitMQ 用户及权限..."
|
||
systemctl enable rabbitmq-server
|
||
systemctl start rabbitmq-server
|
||
RABBITMQ_USERS=$(rabbitmqctl list_users -q)
|
||
if awk '$1 == "openstack" { found = 1 } END { exit !found }' <<< "$RABBITMQ_USERS"; then
|
||
rabbitmqctl change_password openstack openstack
|
||
else
|
||
rabbitmqctl add_user openstack openstack
|
||
fi
|
||
rabbitmqctl set_permissions -p / openstack '.*' '.*' '.*'
|
||
|
||
log_info "配置 Memcached..."
|
||
backup_config /etc/sysconfig/memcached
|
||
sed -i '/^[[:space:]]*OPTIONS=/d' /etc/sysconfig/memcached
|
||
echo 'OPTIONS="-l 127.0.0.1,::1,controller"' >> /etc/sysconfig/memcached
|
||
systemctl enable memcached
|
||
systemctl restart memcached
|
||
|
||
log_info "配置 Etcd..."
|
||
backup_config /etc/etcd/etcd.conf
|
||
cat > /etc/etcd/etcd.conf <<'EOF'
|
||
#[Member]
|
||
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
|
||
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
|
||
ETCD_NAME="controller"
|
||
|
||
#[Clustering]
|
||
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://controller:2380"
|
||
ETCD_ADVERTISE_CLIENT_URLS="http://controller:2379"
|
||
ETCD_INITIAL_CLUSTER="controller=http://controller:2380"
|
||
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-01"
|
||
ETCD_INITIAL_CLUSTER_STATE="new"
|
||
EOF
|
||
systemctl enable etcd
|
||
systemctl restart etcd
|
||
|
||
log_info "配置 Keystone 数据库连接及 Fernet 令牌..."
|
||
backup_config /etc/keystone/keystone.conf
|
||
cat > /etc/keystone/keystone.conf <<'EOF'
|
||
[database]
|
||
connection = mysql+pymysql://keystone:keystone@controller/keystone
|
||
[token]
|
||
provider = fernet
|
||
EOF
|
||
chown root:keystone /etc/keystone/keystone.conf
|
||
chmod 640 /etc/keystone/keystone.conf
|
||
|
||
log_info "同步 Keystone 数据库表结构..."
|
||
su -s /bin/sh -c "keystone-manage db_sync" keystone
|
||
|
||
# 使用 setup 命令初始化密钥库,不删除已有密钥。
|
||
log_info "初始化 Fernet 和 credential 密钥库..."
|
||
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
|
||
keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
|
||
|
||
log_info "初始化 Keystone 管理员及服务端点..."
|
||
keystone-manage bootstrap --bootstrap-password admin \
|
||
--bootstrap-admin-url http://controller:5000/v3 \
|
||
--bootstrap-public-url http://controller:5000/v3 \
|
||
--bootstrap-internal-url http://controller:5000/v3 \
|
||
--bootstrap-region-id RegionOne
|
||
|
||
log_info "配置 Apache HTTP 服务..."
|
||
backup_config /etc/httpd/conf/httpd.conf
|
||
# 删除已有生效的 ServerName,避免重复追加。
|
||
sed -i '/^[[:space:]]*ServerName[[:space:]]/d' /etc/httpd/conf/httpd.conf
|
||
printf '\nServerName controller\n' >> /etc/httpd/conf/httpd.conf
|
||
|
||
WSGI_SOURCE="/usr/share/keystone/wsgi-keystone.conf"
|
||
WSGI_LINK="/etc/httpd/conf.d/wsgi-keystone.conf"
|
||
if [ ! -f "$WSGI_SOURCE" ]; then
|
||
log_err "缺少 Keystone WSGI 配置:$WSGI_SOURCE"
|
||
exit 1
|
||
fi
|
||
# 备份已有普通配置文件;重复运行时更新软链接。
|
||
if [ ! -L "$WSGI_LINK" ]; then
|
||
backup_config "$WSGI_LINK"
|
||
fi
|
||
ln -sfnT "$WSGI_SOURCE" "$WSGI_LINK"
|
||
|
||
log_info "检查 Apache 配置并启动服务..."
|
||
httpd -t
|
||
systemctl enable httpd
|
||
systemctl restart httpd
|
||
|
||
log_info "检查各项服务状态..."
|
||
for service in libvirtd chronyd mariadb rabbitmq-server memcached etcd httpd; do
|
||
if systemctl is-active --quiet "$service"; then
|
||
log_info "$service 状态正常。"
|
||
else
|
||
log_err "$service 未正常运行,请使用 journalctl -u $service 查看日志。"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
log_info "=========================================="
|
||
log_info "OpenStack 控制节点及 Keystone 初始化完成!"
|
||
log_info "控制节点:$CONTROLLER_HOSTNAME ($CONTROLLER_IP)"
|
||
log_info "MariaDB root 密码:123456,已允许远程登录。"
|
||
log_info "RabbitMQ 用户/密码:openstack / openstack"
|
||
log_info "Keystone 管理员/密码:admin / admin,区域:RegionOne"
|
||
log_info "Keystone API:http://controller:5000/v3"
|
||
log_info "=========================================="
|