一、项目简介及准备工作
1.1.虚拟化平台简介
1.1.1.ESXi 8 是什么?
-
定义:
ESXi 8 是 VMware 推出的最新版本 裸机虚拟化管理程序(Hypervisor),属于 VMware vSphere 产品线的核心组件。 -
核心功能:
-
在物理服务器上创建和管理虚拟机(VM)。
-
提供硬件资源的抽象化、池化和动态分配。
-
-
定位:
企业级虚拟化基础设施的基石,适用于数据中心、云计算和虚拟化环境。
1.1.2.ESXi 8 的核心特性
-
性能优化:
-
支持最新硬件(如 Intel Sapphire Rapids 和 AMD EPYC Genoa)。
-
提升虚拟机密度(单主机支持更多 VM)。
-
-
安全性增强:
-
集成 TPM 2.0 和 Secure Boot,支持虚拟机加密。
-
提供基于硬件的安全隔离(如 Intel CET)。
-
-
管理简化:
-
增强的 vSphere Client 界面,支持自动化运维。
-
集成 Kubernetes(通过 Tanzu),支持容器化工作负载。
-
-
存储与网络优化:
-
支持 NVMe over TCP 和 RDMA,提升存储性能。
-
增强网络功能(如 NSX-T 集成)。
-
1.1.3.为什么选择 ESXi 8 构建数据库基础平台?
1. 资源利用率最大化
-
动态资源分配:
根据数据库负载动态调整 CPU、内存和存储资源,避免资源浪费。 -
高密度部署:
单台物理服务器可运行多个数据库实例,降低硬件成本。
2. 高可用性与容灾
-
vSphere HA:
自动检测物理服务器故障,并在其他主机上重启受影响的数据库 VM。 -
vMotion:
支持数据库 VM 的在线迁移,实现零停机维护。 -
备份与恢复:
集成 VMware Data Protection,提供数据库一致性快照。
3. 性能优化
-
NUMA 感知:
优化数据库工作负载的内存访问性能。 -
SR-IOV 支持:
提升网络和存储 I/O 性能,适合 OLTP 和高并发场景。
4. 安全性与合规性
-
虚拟机加密:
保护敏感数据(如客户信息、交易记录)。 -
审计与监控:
集成 vRealize Suite,提供全面的日志和合规性报告。
5. 灵活性与可扩展性
-
混合云支持:
通过 VMware HCX 实现数据库工作负载在本地和云端的无缝迁移。 -
容器化集成:
支持在 VM 中运行 Kubernetes,实现数据库服务的现代化部署。
1.2.项目说明
该项目是一个综合实战项目,重点涉及虚拟化、MySQL 集群和 Shell 脚本,旨在锻炼实操能力。通过参与该项目,深入了解在企业环境中所需的多项知识点,并学习如何通过编写 Shell 脚本实现运维自动化 。
1.3.实验背景
随着信息技术的不断发展和医疗行业的现代化进程,医院的管理系统逐渐向数字化和智能化发展。洛杉矶第一人民医院作为一家大型医疗机构,建立了一个患者就诊历史管理系统,以便患者能方便地通过身份证信息查询自己在医院的就诊记录。这一系统不仅提高了患者的就诊体验,也为医疗服务提供了有效的数据支持。同时,系统的稳定性和安全性在医院运营中显得尤为重要。
然而,随着患者量的增加和数据量的不断增长,原有的物理机器环境在存储和计算能力上逐渐显得疲态,系统的扩展及维护成本逐步上升,面对突发的网络攻击和硬件故障,系统的安全性和可靠性也面临着挑战。为了解决这些问题,医院决定将患者就诊历史管理系统迁移到企业级虚拟化平台上。
企业级虚拟化平台具备灵活的资源调配、高效的负载均衡和良好的安全隔离性,能够在提供高可用性的同时,大幅度降低运维成本。迁移到虚拟化平台后,系统可以实现更好的资源管理和性能优化,并且易于扩展,能够应对未来可能增加的业务需求。同时,虚拟化技术支持的灾难恢复方案能够为医院的就诊历史数据提供更高的保护,确保患者信息安全。
考虑到患者的个人隐私和医疗数据的敏感性,该项目还将注重信息安全的合规性,确保符合相关法规要求,为患者提供更加安全、高效的就医服务。因此,这一迁移项目不仅是技术的升级,更是对医疗服务质量和安全性的一次全面提升。
1.4.实验目的
1. 综合实战项目:课程结合了多个高级技术领域,目的是通过实践把理论知识转化为实际能力,特别是在运维和数据库管理方面。
2. 真实企业案例:通过对接真实企业案例,项目能够帮助理解实际工作场景,避免因虚构项目而带来的不切实际的困扰,促进主动思考和问题解决能力。
3. 实操能力锻炼:强调实操能力的锻炼,不仅关注技术细节,还注重动手能力的提升,包括如何使用 Shell 脚本实现运维自动化,增强其在工作中的实际应用能力。
4. 企业级虚拟化平台与更新软件环境:引入现代虚拟化解决方案,能够接触到最新的工具和技术,为日后在企业中工作打下良好基础。
1.5.实验环境
二、安装企业级虚拟化平台
2.1.VMware 新建虚拟化平台
在 VMware 里新建虚拟机,建立好实验所需的虚拟化环境。
2.2.自定义安装 ESXi 8
建立完成后开机。
在 ESXi 8 安装过程中输入的 runweasel cdromBoot autoPartitionOSDataSize=8192 是一组用于引导和配置安装过程的命令参数,下面为你详细解释每个部分的含义:
runweasel
-
runweasel 是 ESXi 安装程序的启动命令,weasel 实际上是 ESXi 安装程序的内部名称,当你输入 runweasel 时,就会启动 ESXi 安装向导,开始整个安装流程。
cdromBoot
-
cdromBoot 表示从光盘(CD-ROM)启动安装过程。在早期的服务器安装中,使用光盘作为安装介质是比较常见的方式。这里明确指定从光盘引导系统,意味着 ESXi 安装程序会从插入服务器光驱的 ESXi 安装光盘中读取安装文件并进行安装操作。
autoPartitionOSDataSize=8192
-
autoPartition:这表示让安装程序自动对磁盘进行分区。在安装 ESXi 时,磁盘分区是一个重要步骤,autoPartition 选项可以让安装程序根据默认的规则和算法,自动为 ESXi 系统分配磁盘空间,创建必要的分区,而无需用户手动干预分区过程。
-
OSDataSize=8192:OSDataSize 用于指定 ESXi 系统数据分区的大小,单位是兆字节(MB)。这里设置为
8192
,意味着安装程序会自动创建一个大小为 8192 MB(即 8 GB)的系统数据分区,用于存储 ESXi 操作系统的相关数据、配置文件等。
综上所述,runweasel cdromBoot autoPartitionOSDataSize=8192 这一命令组合的作用是:从光盘启动 ESXi 8 的安装程序,让安装程序自动对磁盘进行分区,并将 ESXi 系统数据分区的大小设置为 8GB。
注意:这里系统提示需要断开光盘,再重启。
F2 定制化系统
三、配置 pxe_server 主机
浏览器进入企业级虚拟化平台。
3.1.上传镜像
上传准备好的 rhel9 镜像,等待上传完毕。
3.2.安装 pxe_server 主机
新建虚拟机。
打开 pxe_server 主机。
手动修改完毕,如下图。
注意:要连接光盘。
3.3.准备 pxe_server 主机自动化脚本所需的环境
准备一个主机作为 web 服务器(这里的 IP:192.168.67.170),安装 httpd 服务,配置接下来实验所需的 mysql 软件压缩包和 mysql 主机配置系统所需的 shell 脚本。
3.4.部署自动化脚本
xshell 链接虚拟机。
用 xftp 上传准备好的自动化脚本。
执行脚本。
3.5.自动化脚本代码
#!/bin/bash
echo
echo GET READY FOR ENV,PLEASE WAIT...
# 设置本机yum源
# config rpm repo
repoconfig() {
rm -rf /etc/yum.repos.d/rpm.repo
cat << EOF > /etc/yum.repos.d/rpm.repo
[baseos]
name=BaseOS
baseurl=/mnt/BaseOS
gpgcheck=0
[baseos2]
name=AppStream
baseurl=/mnt/AppStream
gpgcheck=0
EOF
dnf clean all &> /dev/null
mount /dev/sr0 /mnt &> /dev/null
dnf install initscripts -y &> /dev/null
REPORES=$(rpm -qa | grep initscripts &> /dev/null; echo $?)
. /etc/rc.d/init.d/functions
if [ ${REPORES} -eq 0 ];
then
echo_success
echo "--> Local Repo Config Succeessfully."
else
echo_failure
echo "--> Local Repo Config Failed. Please Check."
exit 1
fi
}
# 设置本机IP
# get ip address
getipadd() {
hostname -I &> /dev/null
if [ $? -eq 0 ];
then
echo_success
echo "--> Get IP OK."
else
echo_failure
echo "--> Get IP Failed."
exit 2
fi
#PXE_IP=$(echo $(hostname -I)|awk -F '{print $1}')
PXE_IP=$(hostname -I | cut -d " " -f 1)
PXE_IP_NET=$(echo $PXE_IP | cut -d "." -f 1-3)
PXE_IP_HOST=$(echo $PXE_IP | awk -F "." '{print $4}')
IPCONN=$(nmcli connection show | grep ethernet | awk '{print $1}')
nmcli connection modify ${IPCONN} ipv4.addresses ${PXE_IP}/24
nmcli connection modify ${IPCONN} ipv4.gateway ${PXE_IP_NET}.2
nmcli connection modify ${IPCONN} ipv4.dns ${PXE_IP_NET}.2
nmcli connection modify ${IPCONN} ipv4.method manual
nmcli connection modify ${IPCONN} connection.autoconnect yes
nmcli connection up ${IPCONN} &> /dev/null
echo
echo "Host IP address is ${PXE_IP}"
echo "Host name is $(hostname)"
echo
#echo "NET is ${PXE_IP_NET}"
#echo "IP_HOST is ${PXE_IP_HOST}"
IPCOUNT=$(hostname -I | wc -l)
if [ ${IPCOUNT} -eq 1 ];
then
echo_success
echo "--> IP Address OK"
else
echo_failure
echo "--> IP Address Failed, Please Check..."
exit 3
fi
}
# 安装本机pxe需要的软件
# Install all rpm package
installrpm(){
echo "--> Install packages now, Please wait..."
RPMINST=$(dnf install dhcp-server tftp-server httpd wget -y &> /dev/null;echo $?)
if [ "${RPMINST}" -eq 0 ];
then
echo_success
echo "--> The packages install complete..."
else
echo_failure
echo "--> The packages install failed, Please check..."
exit 4
fi
}
# 配置DHCP
# Config and Starting the dhcp server##
dhcpconfig(){
cat << EOF > /etc/dhcp/dhcpd.conf
option architecture-type code 93 = unsigned integer 16;
subnet ${PXE_IP_NET}.0 netmask 255.255.255.0 {
option routers ${PXE_IP_NET}.2;
option domain-name-servers ${PXE_IP_NET}.2;
range ${PXE_IP_NET}.100 ${PXE_IP_NET}.200;
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server ${PXE_IP};
if option architecture-type = 00:07 {
filename "redhat/EFI/BOOT/BOOTX64.EFI";
}
else {
filename "pxelinux/pxelinux.0";
}
}
class "httpclients" {
match if substring (option vendor-class-identifier, 0, 10) = "HTTPClient";
option vendor-class-identifier "HTTPClient";
filename "http://${PXE_IP}/redhat/EFI/BOOT/BOOTX64.EFI";
}
}
EOF
DHCPRES=$(systemctl restart dhcpd &> /dev/null;echo $?)
if [ ${DHCPRES} -eq 0 ];then
echo_success
echo "--> Service DHCP starting..."
else
echo_failure
echo "--> Service DHCP starting failed, Please check..."
exit 5
fi
}
# 配置tftp,配置UEFI PXE
#/var/lib/tftpboot/
#├── redhat/EFI/BOOT/BOOTX64.EFI 或者 http://${PXE_IP}/redhat/EFI/BOOT/BOOTX64.EFI # Syslinux 提供的 PXE 引导程序
#└── images/
# ├── vmlinuz # Linux 内核
# └── initrd.img # 初始化内存镜像
#└──redhat/EFI/BOOT/grub.cfg # 启动菜单配置文件
# Config and starting the tftp server
tftpconfig(){
TFTP_DIR=/var/lib/tftpboot
rm -rf ${TFTP_DIR}/*
mkdir ${TFTP_DIR}/images/
mkdir ${TFTP_DIR}/redhat/
cp /mnt/isolinux/initrd.img ${TFTP_DIR}/images/
cp /mnt/isolinux/vmlinuz ${TFTP_DIR}/images/
cp -r /mnt/EFI ${TFTP_DIR}/redhat/
chmod -R 755 ${TFTP_DIR}/redhat/
cat << EOF > ${TFTP_DIR}/redhat/EFI/BOOT/grub.cfg
set timeout=1
menuentry 'Install RHEL9.3 Operating System' {
linuxefi images/vmlinuz ip=dhcp inst.ks=http://${PXE_IP}/ks.cfg
initrdefi images/initrd.img
}
EOF
systemctl enable tftp.socket --now &> /dev/null
if [ "$?" -eq 0 ];then
echo_success
echo "--> Service TFTP starting..."
else
echo_failure
echo "--> Service TFTP starting failed, Please check..."
exit 6
fi
}
# 创建共享给客户端rpm网络源
# Creating Client local repo file
clientrepo(){
echo "--> Creating Client local repo file now, Please wait..."
sleep 3
cat << EOF > /var/www/html/rpm.repo
[BaseOS]
name=BaseOS
baseurl=http://$PXE_IP/RHEL-9/BaseOS
gpgcheck=0
[AppStream]
name=AppStream
baseurl=http://$PXE_IP/RHEL-9/AppStream
gpgcheck=0
EOF
}
# 创建共享给客户端mysql源
# createrepo制作mysql源
# Creating Client MySQL repo file
clientmysqlrepo(){
echo "--> Creating Client MySQL repo file now, Please wait..."
sleep 3
if [ -e /var/www/html/mysql ];
then
rm -rf /var/www/html/mysql/*
else
mkdir /var/www/html/mysql
fi
if [ -e /root/mysql.tar.gz ];
then
cp mysql.tar.gz /var/www/html/mysql/
else
wget -q --show-progress http://192.168.67.170/mysql.tar.gz -O /var/www/html/mysql/mysql.tar.gz # 另一台主机共享mysql.tar.gz(192.168.67.170)
fi
# 制作mysql的yum仓库
if [ -e /var/www/html/mysql/mysql.tar.gz ];
then
cd /var/www/html/mysql/
tar xf mysql.tar.gz &> /dev/null
dnf install createrepo -y &> /dev/null
createrepo /var/www/html/mysql/ &> /dev/null
else
echo "Cound not found MySQL Package, Please check..."
exit
fi
cat << EOF > /var/www/html/mysql.repo
[mysql]
name=MySQL
baseurl=http://$PXE_IP/mysql
gpgcheck=0
EOF
}
# 创建kickstart
# Creating ks.cfg
ksfile(){
echo "--> Creating ks.cfg now, Please wait..."
sleep 3
cat << EOF > /var/www/html/ks.cfg
# Generated by Anaconda 34.25.3.8
# Generated by pykickstart v3.32
#version=RHEL9
# Use graphical install
#graphical
text
url --url=http://${PXE_IP}/RHEL-9/
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
# Keyboard layouts
keyboard --xlayouts='us'
# System language
lang en_US.UTF-8
%packages
#@^workstation-product-environment
@^Minimal Install
vim-enhanced
bash-completion
wget
tree
lrzsz
net-tools
psmisc
expect
%end
# Run the Setup Agent on first boot
firstboot --enable
# Generated using Blivet version 3.6.0
ignoredisk --only-use=sda
autopart
# Partition clearing information
clearpart --none --initlabel
# System timezone
timezone Asia/Shanghai --utc
# Root password
rootpw --iscrypted --allow-ssh $6$uzsdS7k7Sx75uUAb$8v8T/DwBtd6vDkvh85HoYUAZ8ktZavD2mGgNSXkgX0.9vtgY0E39xCWRXpLTCeGwRXjFRrsF8wimsU/K0h/OW/
user --name=redhat --password=$6$Pq1XFyFW/hDyZ7gJ$gkJkU76IppE8ZG7wdlnA5VJVHOHsbFgb2nHh.jVvDKVuryzymeR33TUDQRXpgDCvoWGYN.nSYYGs.QV3VJJsN. --iscrypted --gecos="redhat"
%post
wget http://$PXE_IP/rpm.repo -O /etc/yum.repos.d/rpm.repo &> /dev/null
wget http://$PXE_IP/mysql.repo -O /etc/yum.repos.d/mysql.repo &> /dev/null
wget -q --show-progress http://192.168.67.170/mysql.sh -O /root/mysql.sh &> /dev/null
echo redhat | passwd --stdin root &> /dev/null
echo redhat | passwd --stdin redhat &> /dev/null
echo
echo
echo "Welcome to MySQL Database System" >> /etc/issue
echo "" >> /etc/issue
%end
reboot
EOF
}
# 注意上面的mysql.sh需要另一个主机共享,就是上面所准备的环境(192.168.67.170)
# 配置httpd服务,共享yum源
httpiso(){
HTTPISO=/var/www/html/RHEL-9
umount ${HTTPISO} &> /dev/null
mkdir ${HTTPISO} &> /dev/null
mount /dev/sr0 ${HTTPISO} &> /dev/null
if [ "$?" -eq 0 ];then
echo_success
echo "--> The ISO remote repo install ok."
else
echo_failure
echo "--> The ISO remote repo install faied."
exit 7
fi
systemctl enable httpd --now &> /dev/null
if [ "$?" -eq 0 ];then
echo_success
echo "--> Service HTTP starting..."
else
echo_failure
echo "--> Service HTTP starting failed, Please check..."
exit 8
fi
systemctl stop firewalld &> /dev/null
HTTP_CON_RES=$(curl http://${PXE_IP}/RHEL-9/media.repo &> /dev/null;echo $?)
if [ "$HTTP_CON_RES" -eq 0 ];then
echo_success
echo "--> The remote repo test ok."
else
echo_failure
echo "--> The remote repo test failed, Please check."
exit 9
fi
}
firewallconfig(){
systemctl start firewalld
firewall-cmd --permanent --add-service=http --add-service=tftp &> /dev/null
firewall-cmd --reload &> /dev/null
}
#1 config local rpm repo
repoconfig
#2 get ip
getipadd
#3 install rpm package
installrpm
#4 dhcp service config
dhcpconfig
#5 tftp service config
tftpconfig
#6 config client repo file
clientrepo
#7 config MySQL repo file
clientmysqlrepo
#8 ks file generate
ksfile
#9 iso with http
httpiso
#10 firewalld config
firewallconfig
echo
echo "The PXE Server deployed complete."
echo
四、配置 MySQL 主机
4.1.安装 MySQL_Master 和 MySQL_Slave 主机
创建 MySQL_Master 主机。
因为 MySQL 主机要用 pxe 自动化安装,所以这里不设置光盘文件。
重复以上操作,再建一个 MySQL_Slave 主机(创建步骤省略)。
创建好之后如下图:
开机,等待自动安装完毕(前面配置的 pxe_server 主机就是为了给这两台主机提供 pxe 服务的,实现自动化安装系统)。
安装完毕,登录 root 账号,查看 IP。
用 xshell 登录,家目录下以下载 mysql.sh 脚本,直接执行自动化脚本,配置 MySQL 主从服务器。
注意:主服务器在执行 shell 脚本时,需要带上 master。slave 服务器需要交互式输入 master 服务器生成的相关信息,从而构建主从服务器。
4.2.登录 MySQL 查看主从同步状态
注意:密码是 #openLAB123
从库查看主从同步状态。
测试主从同步:主库创建一个数据库,从库能查到主库创建的数据库,说明主从同步完成。
4.3.自动化脚本代码
echo GET READY FOR ENV,PLEASE WAIT...
MYSQLROLE=$1
mysqlinit (){
systemctl stop mysqld &> /dev/null
rm -rf /var/log/mysql*
rm -rf /usr/lib64/mysql
rm -rf /var/lib/mysql
dnf remove mysql mysql84-community-release-el9 -y &> /dev/null
systemctl daemon-reload
dnf install initscripts -y &> /dev/null
. /etc/rc.d/init.d/functions
}
mysqlrepo(){
rpm -i https://repo.mysql.com//mysql84-community-release-el9-1.noarch.rpm &> /dev/null
REPORES=$?
if [ $REPORES -eq 0 ];then
echo_success
echo "--> ENV READY"
else
echo_failure
echo "--> ENV NOT READY,PLEASE CHECK!!!"
exit 1
fi
}
# install mysql package
mysqlinstall(){
echo "--> Install MySQL Server Now, Please wait..."
dnf install mysql mysql-server -y &> /dev/null
rpm -qa | grep mysql-server &> /dev/null
INSRES=$?
if [ $? -eq 0 ]
then
echo_success
echo "--> MySQL install successfully"
else
echo_failure
echo "--> MySQL install failure"
exit 2
fi
systemctl enable mysqld --now &>/dev/null
firewall-cmd --permanent --add-service=mysql &> /dev/null
firewall-cmd --reload &> /dev/null
}
# master config
masterconfig(){
MYSQLTEMPPASS=$(grep "password is generated" /var/log/mysqld.log | awk '{print $NF}' | tail -1)
mysql --connect-expired-password -uroot -p${MYSQLTEMPPASS} -e"
ALTER USER 'root'@'localhost' identified by '#openLAB123';
CREATE USER 'repl'@'%' IDENTIFIED BY '#openLAB123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
QUIT" &> /dev/null
sed -i '/server-id/d' /etc/my.cnf
echo "server-id=22" >> /etc/my.cnf
systemctl restart mysqld
TEMPFILE=$(mktemp -t mysql.mastertemp.XXXXXX)
mysql --connect-expired-password -uroot -p#openLAB123 -e"
SHOW BINARY LOG STATUS\G;
QUIT" &> $TEMPFILE
MYSQLBINFILE=$(grep File ${TEMPFILE} | awk '{print $2}')
MYSQLPOSITION=$(grep Position ${TEMPFILE} | awk '{print $2}')
echo "####################################"
echo " MASTER BINFILE : $MYSQLBINFILE"
echo " MASTER POSITION : $MYSQLPOSITION"
echo "MASTER IP ADDRESS : $(hostname -I)"
echo "####################################"
echo "MySQL role is MASTER"
}
# master config
slaveconfig(){
MYSQLTEMPPASS=$(grep "password is generated" /var/log/mysqld.log | awk '{print $NF}' | tail -1)
mysql --connect-expired-password -uroot -p${MYSQLTEMPPASS} -e"
ALTER USER 'root'@'localhost' identified by '#openLAB123';
QUIT" &> /dev/null
sed -i '/server-id/d' /etc/my.cnf
echo "server-id=23" >> /etc/my.cnf
systemctl restart mysqld
read -p "Please input the MASTER BINFILE: " BINFILE
read -p "Please input the MASTER POSITION: " POSITION
read -p "Please input the MASTER IP: " MASTERIP
mysql --connect-expired-password -uroot -p#openLAB123 -e"
CHANGE REPLICATION SOURCE TO SOURCE_HOST='${MASTERIP}',SOURCE_USER='repl',SOURCE_PASSWORD='#openLAB123',SOURCE_LOG_FILE='${BINFILE}',SOURCE_LOG_POS=${POSITION},GET_SOURCE_PUBLIC_KEY=1;
START REPLICA;
QUIT" &> /dev/null
TEMPFILE=$(mktemp -t mysql.slavetemp.XXXXXX)
mysql --connect-expired-password -uroot -p#openLAB123 -e"
show replica status \G
QUIT" &> $TEMPFILE
MYSQL_IO_STA=$(grep Replica_IO_Running ${TEMPFILE} | awk '{print $2}')
MYSQL_SQL_STA=$(grep Replica_SQL_Running ${TEMPFILE} | awk '{print $2}')
echo "--> Testing MySQL Cluster Now..."
sleep 5
if [ "${MYSQL_IO_STA}" == "Yes" -o "MYSQL_SQL_STA" == "Yes" ];
then
echo_success
echo "Replica Status Ok."
else
echo_failure
echo "Replica Status Failed. Please Check."
fi
echo "MySQL role is SLAVE"
}
mysqlinit
#mysqlrepo
mysqlinstall
if [ "${MYSQLROLE}" == "master" ];
then
masterconfig
else
slaveconfig
fi