DELL服务器之系统部署环境初准备

本人习惯通过cobbler部署物理机系统,那我就来说说部署系统前需要做哪些准备

1.BIOS设置是否符合标准。比如F1/F2错误提示、系统启动顺序、是否有开启PXE启动等。

2.你从哪个网卡进行pxe引导,cobbler部署需确定对应服务器网卡的MAC地址。

3.做磁盘阵列,此项是最耗费时间的。也是这个原因,才有了这个文档。

4.更改idrac root用户的密码,并新增一个组内通用用户。



一、racadm环境部署及文档说明

此文档仅适用于dell且配置了iDRAC远程管理卡的机器(主要是配置了idrac ip,方便远程连接)。全文脚本依赖于racadm环境,需在放置脚本的服务器上安装srvadmin包。

环境部署如下:

# wget  http://downloads.dell.com/FOLDER03574555M/1/OM-MgmtStat-Dell-Web-LX-8.3.0-1908_A00.tar.gz -P /tmp/
# tar zxvf OM-MgmtStat-Dell-Web-LX-8.3.0-1908_A00.tar.gz
# cd /tmp/linux/rac/RHEL6/x86_64/
# rpm -ivh srvadmin*
# ln -s /opt/dell/srvadmin/bin/racadm /usr/bin/racadm

具体命令和用法,我就不说了,大家可以参考以下手册

http://www.dell.com/support/manuals/us/en/19/idrac7-8-with-lc-v2.20.20.20/iDRAC_RACADM_Pub-v3/storage?guid=GUID-9E3676CB-B71D-420B-8C48-C80ADD258E03&lang=en-us

二、 脚本说明

脚本部分一共包含三部分。

  • hosts.conf文件:脚本从文本文件中获取ip信息,网卡号,需配置的阵列类型等。
  • run.sh:运行脚本,此脚本从hosts.conf文件中获取信息并后台执行bin目录下的脚本,实现多机器并发。
  • bin目录:此目录放置实现网卡获取、用户添加、raid配置等脚本。

1.hosts.conf文件内容,初步定义如下。

# NIC_NUM后的数字表示第几块网卡,电口用网口3或4进行PXE安装,光口用网口1或2进行PXE安装 
# raid方式:[ RAID: no | RAID: 0 | RAID: 5 ] 
# RAID: 5:方式一:有2块500G左右盘做sda ,其余HDD做sdb;   方式二:所有HDD大小一样,划分300G做sda,剩下做sdb。两种方式都会判断是否有SSD)
# idrac ip书写方式有两种:192.168.1.1-10或每一行写一个IDRAC IP
NIC_NUM: 1
RAID: 5
192.168.1.1-10

2.run.sh脚本内容

#!/bin/bash
# chenss
# date : 2016-09-10
start=`date +%s`
NicGetMac=‘/data/script/idrac/bin/NicMacGet.sh‘
CreateRaid=‘/data/script/idrac/bin/CreateRaid.sh‘
AddUser=‘/data/script/idrac/bin/AddUser.sh‘
#Check=‘/data/script/idrac/bin/CheckBios.sh‘
idrac_file=‘/data/script/idrac/hosts.conf‘
cat << EOF 
########## please option your choice: [1-3] ############
(1) Get server NIC MAC
(2) Create RAID
(3) Add idrac user and change root password
(*) exit script
########################################################
EOF
read -p "please option your choice: " choice
if [[ $choice -eq 1 ]]; then
    script="$NicGetMac"
elif [[ $choice -eq 2 ]]; then
    script="$CreateRaid"
elif [[ $choice -eq 3 ]]; then
    script="$AddUser"
#elif [[ $choice -eq 4 ]]; then
#    script="$Check"
else
    exit 1
fi
if egrep -v ‘^#|^$|^NIC|^RAID‘ $idrac_file | grep ‘[^[:digit:]].*-‘ &> /dev/null; then
    menu_ipseq=‘1‘
else
    menu_ipseq=‘2‘
fi

function SEQ {
egrep -v ‘^#|^$‘ $idrac_file | grep ‘[^[:digit:]].*-‘ | while read idracs; do
    prefix=`echo $idracs | awk -F ‘[.-]‘ ‘{print $1"."$2"."$3}‘`
    begin=`echo $idracs | awk -F ‘[.-]‘ ‘{print $4}‘`
    end=`echo $idracs | awk -F ‘[.-]‘ ‘{print $5}‘`
    for i in `seq ${begin} ${end}`; do
        {   
        idrac_ip=${prefix}.$i
        if [ "`basename $script`" == "NicMacGet.sh" ]; then
            NUM=`grep ‘^NIC‘ $idrac_file | awk ‘{print $2}‘`
            sh $script $idrac_ip $NUM 
        elif [ "`basename $script`" == "CreateRaid.sh" ];  then
            raid_level=`egrep ‘^RAID‘ $idrac_file | awk ‘{print $2}‘`
            sh $script $idrac_ip $raid_level
        elif [ "`basename $script`" == "AddUser.sh" ]; then
            sh $script $idrac_ip
        elif [ "`basename $script`" == "CheckBios.sh" ]; then
            sh $script $idrac_ip
        else
            echo "input script error!"
        fi
        }&  
    done
    wait
#read -p "please option your choice: " choice
done
}

function NOSEQ {
egrep -v ‘^#|^;|^$‘ $idrac_file | grep ‘^[[:digit:]].*$‘ | while read idracs; do
    {   
    idrac_ip=`echo $idracs | awk ‘{print $1}‘`
    if [ "`basename $script`" == "NicMacGet.sh" ]; then
        NUM=`grep ‘^NIC‘ $idrac_file | awk ‘{print $2}‘`
        sh $script $idrac_ip $NUM
    elif [ "`basename $script`" == "CreateRaid.sh" ];  then
        raid_level=`egrep ‘^RAID‘ $idrac_file | awk ‘{print $2}‘`
        sh $script $idrac_ip $raid_level
    elif [ "`basename $script`" == "AddUser.sh" ]; then
        sh $script $idrac_ip
    else
        echo "input script error!"
    fi
    }&  
wait
#read -p "please option your choice: " choice
done
}
case $menu_ipseq in
1) SEQ;;
2) NOSEQ;;
*) echo "usage: error,please check script!"
esac
over=`date +%s`
echo "use time : `expr $over - ${start}`s"

3.bin目录下脚本内容

1)获取对应pxe引导网卡的mac地址

#!/bin/bash
# chenss
# date : 2016-09-09
#
user=‘root‘
passwd=‘calvin‘
get_nic () {
case $2 in
1)racadm -r $1 -u $user -p $passwd  getsysinfo -s 2> /dev/null | egrep ‘1-1-1‘ | awk -v ip="$1" ‘BEGIN{FS="="} {print ip"\t"$2};‘;;
2)racadm -r $1 -u $user -p $passwd  getsysinfo -s 2> /dev/null | egrep ‘1-2-1|2-1-1‘ | awk -v ip="$1" ‘BEGIN{FS="="} {print ip"\t"$2};‘;;
3)racadm -r $1 -u $user -p $passwd  getsysinfo -s 2> /dev/null | egrep ‘1-3-1|3-1-1‘ | awk -v ip="$1" ‘BEGIN{FS="="} {print ip"\t"$2};‘;;
4)racadm -r $1 -u $user -p $passwd  getsysinfo -s 2> /dev/null | egrep ‘1-4-1|4-1-1‘ | awk -v ip="$1" ‘BEGIN{FS="="} {print ip"\t"$2};‘;;
*)racadm -r $1 -u $user -p $passwd  getsysinfo -s 2> /dev/null | egrep ‘Ethernet‘ | awk -v ip="$1" ‘{print ip":\t"$0};‘;;
esac
}
get_nic $1 $2

2)添加中idrac用户,并更改root用户的密码。

#!/bin/bash
# chenss
# date : 2016-09-09
#
user=‘root‘
pawd=‘calvin‘
newpawd=‘Chenss.New‘
adduser=‘chenss‘
addpawd=‘chensspw‘
function useradd {
racadm -r $1 -u $user -p $pawd set idrac.users.15.username $adduser &> /dev/null
racadm -r $1 -u $user -p $pawd set idrac.users.15.password $addpawd &> /dev/null
racadm -r $1 -u $user -p $pawd set idrac.users.15.Privilege 0x1ff &> /dev/null
racadm -r $1 -u $user -p $pawd set idrac.users.15.enable enabled &> /dev/null
}
function chpawd {
racadm -r $1 -u $adduser -p $addpawd set idrac.users.2.password $newpawd &> /dev/null
}
useradd $1
if racadm -r $1 -u $adduser -p $addpawd get BIOS.SysInformation.SystemServiceTag &> /dev/null; then
    echo -e "$1:\t user JPush add \e[0;32;1msuccess\e[0m!"
else
    echo -e "$1:\t user JPush add \e[40;31;5mfalse\e[0m,please re-add!"
fi
chpawd $1
if racadm -r $1 -u $user -p $newpawd get BIOS.SysInformation.SystemServiceTag &> /dev/null; then
    echo -e "$1:\t user root password changed \e[0;32;1msuccess\e[0m!"
else
    echo -e "$1:\t user root password changed \e[40;31;5mfalse\e[0m,please check!"
fi

3)以下脚本包含磁盘阵列创建、BIOS F1/F2错误提示关闭、设置硬盘为第一启动项,网卡为第二启动项。

#!/bin/bash
# chenss
# date : 2016-09-11
#
user=‘root‘
passwd=‘calvin‘
#controller=`racadm -r $1 -u $user -p $passwd storage get controllers --nocertwarn | egrep "RAID"`
controller=‘RAID.Integrated.1-1‘
pdisks=`racadm -r $1 -u $user -p $passwd storage get pdisks -o -p Status,State,Size,MediaType --nocertwarn 2> /dev/null | egrep ‘Disk.Bay|Status|State|Size|MediaType‘`
HDD_SYS_NUM=`echo $pdisks | xargs -n 14 | awk ‘$10 < 600 && $10 > 500 {print $1}‘ | wc -l`
HDD_SYS_STATE=`echo $pdisks | xargs -n 14 | awk ‘$10 < 600 && $10 > 500 {print $7}‘ | uniq`
HDD_SYS=`echo $pdisks | xargs -n 14 | awk ‘$10 < 600 && $10 > 500 {print $1}‘`
#HDD_SYS_VD=`echo $HDD_SYS | awk ‘{print $1}‘ | sed "s/,/\n/g" | sed  "s/\n/,/g" | sed ":label;N;s/\n/,/;b label"`
HDD_SYS_VD=`echo $HDD_SYS | awk ‘gsub(/ /,",")‘`
SSD_NUM=`echo $pdisks | xargs -n 14 | awk ‘$NF == "SSD" {print $1}‘ | wc -l`
SSD=`echo $pdisks | xargs -n 14 | awk ‘$NF=="SSD" {print $1}‘`
SSD_STATE=`echo $pdisks | xargs -n 14 | awk ‘$NF=="SSD" {print $7}‘ | uniq`
HDD_NUM=`echo $pdisks | xargs -n 14 | awk ‘$10 > 1000 {print $1}‘ | wc -l`
HDD_STATE=`echo $pdisks | xargs -n 14 | awk ‘$10 > 1000 {print $7}‘ | uniq`
HDD=`echo $pdisks | xargs -n 14 | awk ‘$10 > 1000 {print $1}‘`
HDD_VD=`echo $pdisks | xargs -n 14 | awk ‘$10 > 1000 && $NF=="HDD" {print $1}‘ | sed  "s/\n/,/g" | sed ":label;N;s/\n/,/;b label"`
vdisks=`racadm -r $1 -u $user -p $passwd storage get vdisks -o -p Status,State,Size,MediaType --nocertwarn 2> /dev/null | egrep ‘Disk.Virtual|Disk.Bay|Status|State|Size|MediaType‘`
vdisk_sys_NUM=`echo $vdisks | xargs -n 17 | awk ‘$10="Raid-1 && $12 < 600 && $12 > 500" {print $1}‘ | wc -l`
vdisk_sys_raid=`echo $vdisks | xargs -n 17 | awk ‘"$10==Raid-1" && $13 < 600 && $13 > 500 {print $10}‘`
vdisk_sys=`echo $vdisks | xargs -n 17 | awk ‘"$10==Raid-1" && $13 < 600 && $13 > 500 {print $1}‘`
power_status=`racadm -r $1 -u $user -p $passwd serveraction powerstatus --nocertwarn | egrep -o ‘ON|OFF‘`
# delete jobqueue
function jobdel {
local jobc=`racadm -r $1 -u $user -p $passwd jobqueue delete --all --nocertwarn 2> /dev/null | egrep -o ‘cancelled by the user‘`
if [ "$jobc" != "cancelled by the user" ]; then
    echo "$1: job delete all false!"
    exit 1
fi
sleep 1
}

# job submit
function jobsub {
racadm -r $1 -u $user -p $passwd jobqueue create $controller -s TIME_NOW --realtime --nocertwarn &> /dev/null
sleep 3
while true; do
local jobpcert=`racadm -r $1 -u $user -p $passwd jobqueue view --nocertwarn | awk -F "=" ‘/Percent Complete/ {print $2}‘`
if [  "$jobpcert" == "" ]; then
    echo "$1: jobqueue no task. " 
    exit
elif echo $jobpcert | egrep ‘100‘ &> /dev/null; then
    break
fi
sleep 10
done
jobdel $1
}
# 判断是否有2块558G左右的系统盘
function SYSTEM_RAID  {
#jobdel $1 
if [ $HDD_SYS_NUM -eq 2 ]; then
    if [ "$HDD_SYS_STATE" == "Online" -o "$HDD_SYS_STATE" == "Ready" ]; then 
        racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r1 -pdkey:$HDD_SYS_VD --nocertwarn &> /dev/null || echo "$1: TWO 558G HD raid1 create false." `exit`
        jobsub $1
    else 
        for i in $HDD_SYS; do 
            racadm -r $1 -u $user -p $passwd storage converttoraid:$i --nocertwarn &> /dev/null
        done 
        jobsub $1 
        sleep 3
        racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r1 -pdkey:$HDD_SYS_VD --nocertwarn &> /dev/null || echo "$1: TWO 558G HD raid1 create false."  `exit`
        jobsub $1
        sleep 3
    fi
fi
}

# 转换所有磁盘格式为nonraid
function NORAID {
#jobdel $1
if  echo $HDD_STATE | egrep ‘Ready|Online‘; then 
for i in $HDD; do 
    racadm -r $1 -u $user -p $passwd storage converttononraid:$i --nocertwarn &> /dev/null 
done
sleep 1
jobsub $1 
sleep 3
fi
}

# 转换硬盘模式为TORAID
function HDD_TORAID {
#jobdel $1
if  echo $HDD_STATE | egrep ‘Non-Raid‘ &> /dev/null;then
for i in $HDD; do
    racadm -r $1 -u $user -p $passwd storage converttoraid:$i --nocertwarn &> /dev/null
done
sleep 1
jobsub $1
sleep 3
fi
}

# HD单盘做raid0
function HDD_RAID0 {
for i in $HDD; do
    racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r0 -pdkey:$i --nocertwarn &> /dev/null || echo "$1: raid 0 create flase." `exit`
done
sleep 1
jobsub $1
sleep 3
}

# 包含2块558G系统盘的raid方式
function RAID15 {
racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r5 -pdkey:$HDD_VD --nocertwarn &> /dev/null || echo "$1: raid1 + raid 5 create false." `exit`
sleep 1
jobsub $1
sleep 3
} 
# 不包含2块500G系统盘的创建方式
function RAID5 {
racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r5 -size 300g -pdkey:$HDD_VD --nocertwarn &> /dev/null || echo "$1: 300g sda create false." `exit`
sleep 1
racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r5 -pdkey:$HDD_VD --nocertwarn &> /dev/null || echo "$1: raid5 sdb create false." `exit`
sleep 3
jobsub $1
}
# 判断是否有SSD,有则单盘做raid0
function SSD_RAID0 {
if  echo $SSD_STATE | egrep ‘Non-Raid‘ &> /dev/null ; then
    for i in $SSD; do
        racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r0 -pdkey:$SSD --nocertwarn &> /dev/null || echo "$1: SSD RAID create false." `exit`
    done
    jobsub $1
    sleep 1
elif echo $SSD_STATE | egrep ‘Online|Ready‘ &> /dev/null; then
    for i in $SSD; do
        racadm -r $1 -u $user -p $passwd storage createvd:$controller -rl r0 -pdkey:$SSD --nocertwarn  &> /dev/null || echo "$1: SSD RAID create false." `exit`
    done
    sleep 3
    jobsub $1
fi
}

function BiosSet {
local default_Seq=`racadm -r $1 -u $user -p $passwd get BIOS.BiosBootSettings.BootSeq 2> /dev/null | awk -F "[=.]" ‘/BootSeq/ {print $2}‘`
local BiosErrPrompt=`racadm -r $1 -u $user -p $passwd get BIOS.MiscSettings.ErrPrompt | egrep -o ‘Disabled|Enabled‘`
# BIOS F1/F2 ErrPrompt
if [ "$BiosErrPrompt" == "Enabled" ]; then
    racadm -r $1 -u $user -p $passwd set BIOS.MiscSettings.ErrPrompt Disabled &> /dev/null || echo "$1: BIOS ErrPrompt is Enabled.please change Disabeld" `exit`
fi
# BIOS BOOT Seq 
if [ "$default_Seq" != "HardDisk" ]; then
    BOOTSEQ="HardDisk.List.1-1,NIC.Integrated.1-1-1,NIC.Integrated.1-2-1,NIC.Integrated.1-3-1,NIC.Integrated.1-4-1"
    racadm -r $1 -u $user -p $passwd set BIOS.BiosBootSettings.BootSeq $BOOTSEQ &> /dev/null || echo "$1: BootSeq change false." `exit`
fi
racadm -r $1 -u $user -p $passwd jobqueue create BIOS.Setup.1-1 &> /dev/null 
if [ $? -eq 0 ]; then
    while true; do
    local jobpcert=`racadm -r $1 -u $user -p $passwd jobqueue view --nocertwarn | awk -F "=" ‘/Percent Complete/ {print $2}‘`
    if [  "$jobpcert" == "" ]; then
          echo "$1: jobqueue no task. " 
          exit
    elif echo $jobpcert | egrep ‘100‘ &> /dev/null; then
        break
    fi
    sleep 10
    done
    jobdel $1               
fi
}

############################# 以上均为变量与函数,下部分为执行部分######################################
# check power status; if power off ; then power up
if [ "$power_status" == "OFF" ]; then
    racadm -r $1 -u $user -p $passwd serveraction powerup --nocertwarn &> /dev/null || echo "server power start false." `exit`
    sleep 3
elif [ "$power_status" == "ON" ]; then
    echo "$1: server power up!"
else
    echo "$1: server abnormal"
fi
# clear jobqueue
jobdel $1
# clean raid configuration
jobreset=`racadm -r $1 -u $user -p $passwd storage resetconfig:$controller --nocertwarn 2> /dev/null | egrep -o "successfully|No virtual disks"`
sleep 2
if [ "$jobreset" == "successfully" ]; then 
    jobsub $1
elif [ "$jobreset" == "No virtual disks" ]; then
    echo "$1: No virtual disks,keep on install."
else
    echo "$1: clean all raid config false!"
    exit 2
fi

if [ "$2" == "no" ]; then
    SYSTEM_RAID $1 $2
    NORAID $1 $2
elif [ "$2" == "0" ]; then
    SYSTEM_RAID $1 $2
    HDD_TORAID $1 $2
    HDD_RAID0 $1 $2    
elif [ $2 -eq 5 -a $SSD_NUM -eq 0 ]; then
    HDD_TORAID $1
    if [ $HDD_SYS_NUM -eq 2 ]; then
        SYSTEM_RAID  $1 $2
        RAID15 $1 $2     
    elif [ $HDD_SYS_NUM -eq 0 ]; then
        RAID5 $1 $2
    fi  
elif [ $2 -eq 5 -a $SSD_NUM -gt 0 ]; then 
    HDD_TORAID $1 $2
    if [ $HDD_SYS_NUM -eq 2 ]; then
        SYSTEM_RAID $1 $2
        RAID15 $1 $2
        SSD_RAID0 $1 $2
    elif [ $HDD_SYS_NUM -eq 0 ]; then
        RAID5 $1 $2
        SSD_RAID0 $1 $2 
    fi
fi
BiosSet $1
racadm -r $1 -u $user -p $passwd serveraction powercycle --nocertwarn &> /dev/null || echo "server power restart false."
时间: 2024-10-07 21:34:44

DELL服务器之系统部署环境初准备的相关文章

Dell服务器之配置ipmi远程console管理

1.启动服务器,按F2键进入BIOS设置 Serial Communication: Serial Communication......On with Console Redirection via COM2 External Serial Connector...COM2 2.进入系统,修改/boot/grub/menu.1st default=2 timeout=15 kernel /boot/kernel ro root=/dev/sda1 console=tty0 console=tt

linux服务器之系统用户配置文件介绍

用户配置文件用户信息文件:/etc/passwd影子文件:/etc/shadow组信息文件:/etc/group组密码文件:/etc/gshadow在Linux中主要通过用户配置文件来查看和修改用户信息 /etc/passwdaccount:password:UID:GID:GECOS:directory:shell用户名称 密码标志 UID GID 用户说明 家目录 登录之后的shell x表示用户有密码,真正的密码在shadow文件中 UID:0超级用户,1-499系统用户(也叫伪用户,不能

Dell服务器之常用管理命令

具体信息    指令 查看机器型号    # dmidecode | grep "Product" 查看厂商    # dmidecode| grep  "Manufacturer" 查看序列号    # dmidecode | grep  "Serial Number" 查看CPU信息    # dmidecode | grep  "CPU" 查看CPU个数    # dmidecode | grep  "Sock

零成本搭建WDS轻量级系统批量部署环境视频课程

因为实际工作需要搭建过WDS系统批量部署服务器,在自己动手搭建之前在网路上学习过一些资料,但实际操作过程中总是有很多问题或注意事项没有被提及,让自己的WDS服务器部署过程耗费了很多时间和精力.我一直就想把部署过程中特别需要注意的部分融进一个系列的教程中,让学习者可以参照流程轻松实现学习目的.于是我就利用可用时间录制了这个实用课程:<零成本搭建WDS轻量级系统批量部署环境视频课程>. 学习目标在Windows Server 2012R2上使用系统自带的WDS服务搭建Windows7系统批量部署环

使用MDT2013部署Win8系统之五-配置MDT服务器之添加任务序列

在本篇中我们来看一下如何配置任务序列.那么我们首先来看一下任务序列是做什么的呢?任务序列主要用于操作系统部署.捕获模板机系统,然后在捕获后再做一个标准任务.下面我们就来看看如何为安装操作系统创建标准任务序列 添加任务序列,右击"TaskSequence"->"New TaskSequence" 输入任务ID和任务名称,以便分辨具体任务,这个描述的名称到时会在部署的时候看到,所以我们在定义描述时一定要确保一目了然 因为是全新安装,所以选择"Standa

部署环境:基于fastcgi的主机服务分离的LAMP

一.FastCgi与PHP-fpm 参考: http://www.mike.org.cn/articles/what-is-cgi-fastcgi-php-fpm-spawn-fcgi/ 二.LAMP分离架构 资源规划: 静态层:172.16.1.1,httpd服务器 动态层:172.16.1.2,PHP服务器,启动php-fpm 数据层:172.16.1.3, mysql服务器,lvm 三.数据库服务器搭建 略,参考上一篇:部署环境:LAMP+Xcache 四.httpd服务器的搭建 略,参考

在vmware虚拟机中安装centos系统并使用LNMP安装部署环境

一.介绍:题目有点绕口,大概意思就是分两步完成,首先在vmware虚拟机中安装centos系统,然后在centos系统中使用lnmp安装包安装项目部署环境.      准备工作(很重要,所需安装软件如果都没找对,怎么能安装成功) 1.下载vmware,这个好找,直接百度搜索“vmware 下载”,能找到安装软件. 2.下载CentOS,这个需要注意点: 如果系统是32位就点这个:http://mirror.symnds.com/distributions/CentOS-vault/6.3/iso

Linux系统配置及服务管理_第01章系统部署

大家好,我是"霸王卸甲"是一个新博主,从今天开始每日在这里为大家更新一篇关于linux方面的文章,如果有问题或者文章有错误的地方请大家私信我,谢谢. 一.GNU/Linux 的历史:自由软件之父 Richard M. Stallman 1984 GNU Copyleft OpenSource Free GPL 既然是历史,就让它成为历史吧......但请记住他们:Linux 之父 林纳斯?本纳第克特?托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑

从零开始搭建系统3.3——图片服务开发及部署

从零开始搭建系统3.3--图片服务开发及部署 原文地址:https://www.cnblogs.com/provence666/p/8638594.html