ThatManK Mobile Article

宿主机配置

Category: 运维 Tutorial: K8s初级 Published: 2026-04-07 13:58 Views: 26 Likes: 0 Comments: 0
#!/bin/bash

PKGS_DEFAULT_LIST=(
    wget
    curl
    sysstat
    strace
    vim-enhanced
    nscd
    sudo
    kernel
    glibc
    openssl
    bash
    redhat-lsb-core
    net-tools
    tcpdump
    pciutils
    rsync
    chrony
    gcc
    cloud-utils-growpart
    fuse
    fuse-libs
    nfs-utils
    pigz
    socat
    conntrack
    zlib
    deltarpm
    pciutils
    bash-completion
    yum-utils
    pam-devel
    sshpass
    gcc
    gcc-c++
    automake
    libtool
    zlib-devel
    glib2-devel
    bzip2-devel
    libuuid-devel
    spice-protocol
    spice-server-devel
    usbredir-devel
    libaio-devel
)

function 01_config_repo() {
    local REPO_DIR=/etc/yum.repos.d
    if ! grep -q "mirrors.aliyun.com" ${REPO_DIR}/centos.repo; then
        mkdir -p ${REPO_DIR}/bak
        mv ${REPO_DIR}/*.repo ${REPO_DIR}/bak/
        cat >${REPO_DIR}/centos.repo <<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb]
name=CentOS Stream \$releasever - CRB
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF

        cat >${REPO_DIR}/centos-addons.repo <<EOF
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
    fi

    yum clean all
    yum repolist
}

function 02_config_pip {
    mkdir -p /root/.pip
    cat >/root/.pip/pip.conf <<EOF
[global]
index-url=http://mirrors.aliyun.com/pypi/simple/

[install]
trusted-host=mirrors.aliyun.com
EOF
}

function 03_install_packages() {
    yum -y update
    yum -y groupinstall "Development Tools"

    for i in ${PKGS_DEFAULT_LIST[@]}; do
        yum install -y $i
    done

}

function 04_remove_packages() {
    yum -y remove firewalld-* python3-firewall
}

function 05_config_dns() {
    local DNS_FILE=/etc/resolv.conf

    for service in "100.100.2.136" "100.100.2.137"; do
        if ! grep -q "$service" $DNS_FILE; then
            echo "nameserver $service" >>$DNS_FILE
        fi
    done
}

function 06_config_grub() {
    local GRUB_FILE=/etc/default/grub
    cat >$GRUB_FILE <<EOF
GRUB_TIMEOUT=1
GRUB_DISTRIBUTOR="\$(sed 's, release .*\$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M rhgb quiet selinux=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8 nvme_core.io_timeout=4294967295 nvme_core.admin_timeout=4294967295"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
EOF
    grub2-mkconfig -o /boot/grub2/grub.cfg
}

function 07_config_eth0() {
    local NET_DIR=/etc/sysconfig/network-scripts
    find /etc/sysconfig/network-scripts -name "ifcfg-*" | grep -v "ifcfg-lo" | xargs rm -rf
    cat >${NET_DIR}/ifcfg-eth0 <<EOF
BOOTPROTO=dhcp
DEVICE=eth0
ONBOOT=yes
STARTMODE=auto
TYPE=Ethernet
USERCTL=no
EOF
}

function 08_config_selinux() {
    local CONFIG_FILE=/etc/selinux/config
    [ ! -e $CONFIG_FILE ] && return 0
    grep -q '^SELINUX=disabled@@H0@@#39; $CONFIG_FILE || sed -i "s/^SELINUX=.*$/SELINUX=disabled/g" $CONFIG_FILE
}

function 09_config_sshd() {
    cat >/etc/ssh/sshd_config <<EOF
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
AuthorizedKeysFile      .ssh/authorized_keys
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem       sftp    /usr/libexec/openssh/sftp-server
UseDNS no
AddressFamily inet
SyslogFacility AUTHPRIV
PermitRootLogin yes
PasswordAuthentication yes
EOF
    cat >/etc/ssh/ssh_config <<EOF
Host *
        ForwardX11Trusted yes
        SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
        SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
        SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE
        SendEnv XMODIFIERS
        StrictHostKeyChecking no
        UserKnownHostsFile /dev/null
EOF
    systemctl daemon-reload
    systemctl restart sshd
    systemctl status sshd
}

function 10_config_utc_clock() {
    cat >/etc/adjtime <<EOF
0.0 0 0.0
0
UTC
EOF
}

function 11_config_timezone() {
    local time_zone="Asia/Shanghai"
    local dst=/etc/localtime

    if which timedatectl; then
        timedatectl set-timezone "$time_zone"
        timedatectl set-local-rtc 0
    else
        echo 'Asia/Shanghai' >/etc/timezone
        [[ -e $dst ]] && rm -rf $dst
        ln -s /usr/share/zoneinfo/$time_zone $dst
        hwclock -w --utc
    fi
}

function 12_config_chrony() {
    local chrony_file=/etc/chrony.conf
    cat >$chrony_file <<EOF
# Use Alibaba NTP server
# Public NTP
# Alicloud NTP


server ntp.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp1.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp1.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp10.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp11.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp12.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp2.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp2.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp3.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp3.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp4.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp4.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp5.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp5.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp6.aliyun.com minpoll 4 maxpoll 10 iburst
server ntp6.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp7.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp8.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst
server ntp9.cloud.aliyuncs.com minpoll 4 maxpoll 10 iburst

# Ignore stratum in source selection.
stratumweight 0.05

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Enable kernel RTC synchronization.
rtcsync

# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3

# Allow NTP client access from local network.
#allow 192.168/16

# Listen for commands only on localhost.
bindcmdaddress 127.0.0.1
bindcmdaddress ::1

# Disable logging of client accesses.
noclientlog

# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
logchange 0.5

logdir /var/log/chrony
#log measurements statistics tracking
EOF
    systemctl enable chronyd.service
    systemctl restart chronyd.service
    chronyc -n sources -v
}

function 13_config_limits() {
    local dst=/etc/security/limits.conf
    grep -q '^[^#]+nofile\s+65535\s*@@H0@@#39; $dst || cat >>$dst <<EOF
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535
EOF
}

function 14_config_swap_off() {
    swapoff -a
}

function 15_config_dhclient_optimization() {
    local dst=/usr/sbin/dhclient-script

    [ ! -f /usr/sbin/dhclient-script ] && return
    sed -i "s/if arping -D -q -c2/if arping -D -q -c0/g" $dst
}

function 16_config_cpu_performance() {
    ! which tuned && yum install -y tuned
    systemctl enable tuned
    tuned-adm profile virtual-guest
}

function 17_config_journal() {
    local dst=/var/log/journal

    cat /etc/group | grep journal
    if [[ $? == 0 && ! -e $dst ]]; then
        mkdir -p $dst
        chown root:systemd-journal $dst
    else
        return 0
    fi
}

function 18_config_common_sysctl() {
    local dst=/etc/sysctl.conf
    cat >$dst <<EOF
vm.swappiness = 0
kernel.sysrq = 1

net.ipv4.neigh.default.gc_stale_time = 120

net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2

net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_slow_start_after_idle = 0
EOF
}

function 19_config_nvme() {
    lsinitrd /boot/initramfs-$(uname -r).img | grep nvme && return
    mkdir -p /etc/dracut.conf.d
    # centos 7
    # echo 'add_drivers+=" nvme nvme-core nvme-fabrics nvme-fc nvme-rdma nvme-loop nvmet nvmet-fc "' >/etc/dracut.conf.d/nvme.conf
    # centos 8
    echo 'add_drivers+=" nvme nvme-core nvme-fabrics nvme-fc nvme-rdma nvme-loop nvmet nvmet-fc nvme-tcp "' >/etc/dracut.conf.d/nvme.conf
    dracut -v -f
    lsinitrd /boot/initramfs-$(uname -r).img | grep nvme
}

function 20_config_disable_nouv() {
    mkdir -p /etc/modprobe.d
    cat >/etc/modprobe.d/blacklist-nouv.conf <<-EOF
blacklist nouveau
options nouveau modeset=0
EOF
    dracut -v -f
}

function 21_config_virtio() {
    local dst=/etc/dracut.conf
    lsinitrd /boot/initramfs-$(uname -r).img | grep virtio && return

    if ! cat $dst | grep -v "^#" | grep "virtio"; then
        echo 'add_drivers+="virtio_blk virtio_scsi virtio_net virtio_pci virtio_ring virtio"' >>$dst
        dracut -v -f
    fi

    lsinitrd /boot/initramfs-$(uname -r).img | grep virtio
}

function 22_install_go() {
    wget -O - https://golang.google.cn/dl/go1.20.4.linux-amd64.tar.gz | tar -xvz -C /usr/local
    cat >>/etc/profile <<EOF
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
export GOROOT=/usr/local/go
export PATH=\$PATH:\$GOROOT/bin
export GOPATH=/go
export PATH=\$PATH:\$GOPATH/bin
EOF
    export GO111MODULE=on
    export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
    export GOROOT=/usr/local/go
    export PATH=$PATH:$GOROOT/bin
    export GOPATH=/go
    export PATH=$PATH:$GOPATH/bin
    which go && go install github.com/beego/bee/v2@latest
    which bee
}

function 23_install_qemu() {
    yum -y remove qemu-kvm
    find / -name "qemu-kvm" | xargs rm -rf
    find / -name "qemu-img" | xargs rm -rf

    git clone https://github.com/skvadrik/re2c.git re2c
    cd re2c
    mkdir -p m4
    ./autogen.sh && ./configure --prefix=/usr && make -j$(getconf _NPROCESSORS_ONLN)
    make install
    cd ..
    rm -rf re2c
    re2c -v

    git clone https://github.com/ninja-build/ninja.git
    cd ninja
    ./configure.py --bootstrap
    cp ninja /usr/bin/
    cd ..
    rm -rf ninja

    rpm -e --nodeps pixman
    wget https://www.cairographics.org/releases/pixman-0.42.2.tar.gz
    tar -xf pixman-0.42.2.tar.gz
    cd pixman-0.42.2
    ./configure
    make && make install
    cd ..
    rm -rf pixman-*
    export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/"

    wget https://download.qemu.org/qemu-8.0.0.tar.xz
    if [ $? -ne 0 ]; then
        echo "qemu-8.0.0.tar.xz download failed !!!!"
        rm -rf qemu-8.0.0.tar.xz
        return
    fi

    tar -xf qemu-8.0.0.tar.xz
    cd qemu-8.0.0/
    ./configure \
        --enable-debug \
        --enable-vnc \
        --enable-tools \
        --enable-kvm \
        --enable-bzip2 \
        --prefix=/usr/local/qemu \
        --enable-linux-aio \
        --enable-system \
        --block-drv-rw-whitelist=vpc,qcow2,raw,file,host_device,blkdebug,nbd,iscsi,gluster,rbd \
        --target-list="x86_64-softmmu,x86_64-linux-user"
    make -j$(getconf _NPROCESSORS_ONLN)
    make install
    cd .. && rm -rf qemu-*

    ln -s /usr/local/qemu/bin/qemu-system-x86_64 /usr/bin/qemu-kvm
    ln -s /usr/local/qemu/bin/qemu-system-x86_64 /usr/libexec/qemu-kvm
    ln -s /usr/local/qemu/bin/qemu-img /usr/bin/qemu-img
    qemu-kvm --version
    qemu-img --version
}

function clean_log() {
    rm -f /var/log/anaconda.*
    rm -f /var/log/sa/*
    rm -rf /var/log/conman*
    [ -f /var/log/messages ] && >/var/log/messages
    rm -f /var/log/*.[0-9]*
    rm -f dmesg*
    rm -rfv /var/lib/apt/lists/*
    rm -rfv /var/log/installer/syslog
    rm -rfv /var/log/journal/*
    rm -rfv /var/log/installer/cdebconf/questions.dat
    rm -rfv /var/cache/yum/*
    rm -rfv /var/lib/yum/history/*
    rm -rfv /var/lib/dnf/history*
    rm -rfv /var/lib/dhclient/*
    rm -rfv /var/lib/dhcp/*
    rm -rfv /var/lib/aliyun_init/*
    rm -rfv /var/lib/cloud
    rm -rf /var/log/ecsgo.log*
    rm -rf /tmp/*
    rm -f /root/{.bash_history,.viminfo,*.cfg,*.log*}
    rm -rf /root/script

    for i in $(find /var/log/ -type f); do >$i; done

    sed -i "/iZ*Z/d" /etc/hosts
    sed -i "/AliYun/d" /etc/hosts
    sed -i "/debug/d" /etc/hosts

    rm -rfv /tmp/*
    if [[ ! -L /etc/udev/rules.d/70-persistent-net.rules ]]; then
        rm -rfv /etc/udev/rules.d/70-persistent-net.rules
    fi
    sync
    sync
    sync
}

function 24_create_vm() {
    local NET_DIR=/etc/libvirt/qemu/networks

    hostnamectl set-hostname kvm

    # 1. install desktop
    yum clean all
    yum repolist
    yum grouplist
    yum -y groupinstall "Server with GUI"
    systemctl set-default graphical.target

    # 2. install libvirtd
    yum -y install libvirt virt-manager

    systemctl enable libvirtd
    systemctl start libvirtd
    sleep 3

    # 2. config network
    virsh net-destroy default
    virsh net-undefine default
    for i in $(seq 1); do
        name="vbr${i}"
        cat >$NET_DIR/${name}.xml <<EOF
<network>
  <name>${name}</name>
  <forward mode='nat'/>
  <bridge name="${name}" stp='on' delay='0'/>
  <ip address="192.10.${i}.1" netmask='255.255.255.0'>
    <dhcp>
      <range start='192.10.${i}.2' end='192.10.${i}.254'/>
    </dhcp>
  </ip>
</network>
EOF
        virsh net-define $NET_DIR/${name}.xml
        sleep 0.5
        virsh net-start ${name}
        sleep 0.5
        virsh net-autostart ${name}
    done

    reboot
    # rpm -e --nodeps qemu-img
    # ln -s /usr/local/qemu/bin/qemu-img /usr/bin/qemu-img
}

function 25_install_openstack() {
    local NET_DIR=/etc/sysconfig/network-scripts
    local HOST_NAME=openstack
    local IP="100.100.1.10"
    local GW=$(echo $IP | awk -F. '{print $1"."$2"."$3"."2}')
    local REPO_FILE=/etc/yum.repos.d/CentOS-OpenStack-stein.repo
    local GROUP_ID=

    if ! which packstack; then
        # ifconfig eth0 100.100.1.10 netmask 255.255.255.0
        # route add default gw 100.100.1.2
        hostnamectl set-hostname openstack

        # 1. growpart /
        growpart /dev/sda 1
        xfs_growfs /dev/sda1

        # 2. config static ip
        hostnamectl set-hostname $HOST_NAME
        sed -i "/^${IP}/d" /etc/hosts
        echo "$IP $HOST_NAME" >>/etc/hosts
        cat >${NET_DIR}/ifcfg-eth0 <<EOF
DEVICE="eth0"
ONBOOT="yes"
IPV6INIT="no"
IPV4_FAILURE_FATAL="no"
NM_CONTROLLED="no"
TYPE="Ethernet"
BOOTPROTO="static"
IPADDR="$IP"
PREFIX="24"
GATEWAY="$GW"
EOF
        systemctl restart network

        # 3. config ssh
        rm -rf /root/.ssh/*
        ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
        sshpass -p1 ssh-copy-id -i /root/.ssh/id_rsa.pub root@${IP}

        # 4. config repo
        mv /etc/yum.repos.d/epel.repo{,.bak}
        yum -y install centos-release-openstack-stein
        sed -i 's@^#baseurl=http://mirror.centos.org@baseurl=http://mirrors.aliyun.com@' $REPO_FILE
        sed -i 's@^mirrorlist=http://mirrorlist.centos.org@#mirrorlist=http://mirrorlist.centos.org@' $REPO_FILE

        # 5. config volule => /dev/sdb Must mount first!
        yum -y install lvm2
        pvcreate /dev/sdb
        vgcreate cinder-volumes /dev/sdb

        # 6. install openstack
        yum -y install openstack-utils openstack-packstack
        reboot

    else
        yum clean all
        yum repolist

        packstack --allinone \
            --os-neutron-l2-agent=openvswitch \
            --os-neutron-ml2-mechanism-drivers=openvswitch \
            --os-neutron-ml2-tenant-network-types=vxlan \
            --os-neutron-ml2-type-drivers=vxlan,flat \
            --provision-demo=n \
            --os-neutron-ovs-bridge-mappings=extnet:br-ex \
            --os-neutron-ovs-bridge-interfaces=br-ex:eth0 \
            --cinder-volumes-create=n \
            --os-swift-install=n \
            --keystone-admin-passwd=openstack \
            --default-password=openstack

        if [ $? -ne 0 ]; then
            echo "Install failed !"
            return 1
        fi

        # 7. start vm
        . keystonerc_admin
        neutron net-create external_network --provider:network_type flat --provider:physical_network extnet --router:external
        neutron subnet-create \
            --name public_subnet \
            --enable_dhcp=False \
            --allocation-pool=start=100.100.1.100,end=100.100.1.200 \
            --gateway=100.100.1.2 \
            external_network 100.100.1.0/24

        neutron net-create private_network
        neutron subnet-create \
            --name private_subnet \
            --allocation-pool=start=192.10.1.100,end=192.10.1.200 \
            --gateway=192.10.1.2 \
            private_network 192.10.1.0/24

        neutron router-create router1
        neutron router-gateway-set router1 external_network
        neutron router-interface-add router1 private_subnet

        GROUP_ID=$(openstack security group list | grep $(openstack project list | awk '/admin/{print $2}') | awk '{print $2}')
        for rule in $(openstack security group rule list $GROUP_ID | awk '/-/{print $2}'); do
            openstack security group rule delete $rule
        done

        openstack security group rule create --ingress --protocol icmp $GROUP_ID
        openstack security group rule create --ingress --protocol tcp --dst-port 1:65535 $GROUP_ID
        openstack security group rule create --ingress --protocol udp --dst-port 1:65535 $GROUP_ID
        openstack security group rule create --egress --protocol icmp $GROUP_ID
        openstack security group rule create --egress --protocol udp --dst-port 1:65535 $GROUP_ID
        openstack security group rule create --egress --protocol tcp --dst-port 1:65535 $GROUP_ID

        openstack flavor delete m1.small
        openstack flavor create --public m1.small --id 2 --ram 4096 --disk 20 --vcpus 2
        openstack image create --disk-format qcow2 --file centos79.qcow2 centos79 # centos79.qcow2 Must download first!
        openstack server create \
            --image centos79 \
            --flavor m1.small \
            --nic net-id=$(openstack network list | awk '/private_network/{print $2}'),v4-fixed-ip=192.10.1.101 \
            vm1

        sleep 30
        openstack floating ip create external_network --subnet public_subnet --floating-ip-address 100.100.1.101 --port $(neutron port-list | awk '/192.10.1.101/{print $2}')
        openstack server show vm1
        virsh list --all
    fi
}

function stage_1() {
    01_config_repo
    02_config_pip
    03_install_packages
    04_remove_packages
    reboot
}

function stage_2() {
    05_config_dns
    06_config_grub
    07_config_eth0
    08_config_selinux
    09_config_sshd
    10_config_utc_clock
    11_config_timezone
    12_config_chrony
    13_config_limits
    14_config_swap_off
    15_config_dhclient_optimization
    16_config_cpu_performance
    17_config_journal
    18_config_common_sysctl
    19_config_nvme
    20_config_disable_nouv
    21_config_virtio
    reboot
}

function stage_3() {
    22_install_go
    23_install_qemu
    clean_log
}

function stage_4() {
    # 只能选一个 !!
    24_create_vm
    # 25_install_openstack
}

function main() {
    # run one by one !
    # stage_1
    # stage_2
    # stage_3
    # stage_4
    clean_log
}

main