Skip to content

Latest commit

 

History

History
247 lines (184 loc) · 10.3 KB

03. 探寻一键脚本.md

File metadata and controls

247 lines (184 loc) · 10.3 KB

探寻一键脚本

一键脚本里都做了什么?相信不少开发者有过这样的疑问,在完全地熟悉 Shell 语法之前,许多奇葩的语句命令很难完全读懂。在本节,我将大致剖析一键脚本对我们的服务器「进行了哪些改造」,为后文手动部署做好最基本的铺垫。

流程解析

几乎所有的一键脚本,无外乎就是帮我们做两件事:

  1. 安装运行环境
  2. 配置运行环境

对于上节我们使用的脚本,你可以在 这里 查看它的 安装 流程,在 这里 查看到 配置 流程。

  1. 初始化

    # 若出现错误则停止执行脚本
    set -e
    
    # 将变量 CURRENT_DIR 设置为脚本所在的目录
    CURRENT_DIR=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
    
    # 引入一些位于 common.sh 的公共函数,类似 PHP 的 require
    source ${CURRENT_DIR}/../common/common.sh
    
    # 判断当前执行脚本用户是否为 root,若不是则报错并推出
    [ $(id -u) != "0" ] && { ansi -n --bold --bg-red "请用 root 账户执行本脚本"; exit 1; }
    
    # 将变量 MYSQL_ROOT_PASSWORD 设置为 random_string 命令的返回值,也就是随机字符串
    MYSQL_ROOT_PASSWORD=`random_string`
  2. 初始化系统

    function init_system {
        # 将系统本地化配置修改为 en_US.UTF-8
        export LC_ALL="en_US.UTF-8"
        echo "LC_ALL=en_US.UTF-8" >> /etc/default/locale
        locale-gen en_US.UTF-8
        locale-gen zh_CN.UTF-8
    
        # 设置系统时区为 Asia/Shanghai
        ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    
        # 「⚠️重点」更新本地软件源,可理解为刷新可安装软件的列表并记住它们的当前版本
        apt-get update
    
        # 安装名为 software-properties-common 的软件包,用于配置第三方软件源
        apt-get install -y software-properties-common
    
        # 调用 init_alias 函数
        init_alias
    }
    function init_alias {
        # 配置名为 sudowww 的别名,用于快速切换为 WWW_USER 变量所代指的用户
        alias sudowww > /dev/null 2>&1 || {
            echo "alias sudowww='sudo -H -u ${WWW_USER} sh -c'" >> ~/.bash_aliases
        }
    }
  3. 初始化软件源

    function init_repositories {
        # 「⚠️重点」添加第三方软件源,类似于配置 Packagist 镜像
        add-apt-repository -y ppa:ondrej/php
        add-apt-repository -y ppa:nginx/stable
        grep -rl ppa.launchpad.net /etc/apt/sources.list.d/ | xargs sed -i 's/ppa.launchpad.net/launchpad.proxy.ustclug.org/g'
    
        curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
        echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
    
        curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
        echo 'deb https://mirrors.tuna.tsinghua.edu.cn/nodesource/deb_8.x xenial main' > /etc/apt/sources.list.d/nodesource.list
        echo 'deb-src https://mirrors.tuna.tsinghua.edu.cn/nodesource/deb_8.x xenial main' >> /etc/apt/sources.list.d/nodesource.list
    
        # 配置软件源后立即更新
        apt-get update
    }
  4. 安装基础软件包

    function install_basic_softwares {
        # 「⚠️重点」
        # 安装 curl,一款命令行 HTTP 客户端,与 PHP 内的 cURL 扩展作用一致
        # 安装 git,可用于拉取源码等
        # 安装 build-essential,作为编译其它软件的必要基础环境
        # 安装 unzip,可用于解压 Zip 压缩包
        # 安装 supervisor,可用于保证 Laravel 队列处理器持续运行等
        apt-get install -y curl git build-essential unzip supervisor
    }
  5. 安装 PHP

    function install_php {
        # 「⚠️重点」安装 PHP 7.2、PHP 命令、PHP-FPM 以及一大堆常用 PHP 扩展。
        apt-get install -y php7.2-bcmath php7.2-cli php7.2-curl php7.2-fpm php7.2-gd php7.2-mbstring php7.2-mysql php7.2-opcache php7.2-pgsql php7.2-readline php7.2-xml php7.2-zip php7.2-sqlite3
    }
  6. 安装其它软件

    function install_others {
        # 「⚠️重点」由于需要安装 Nginx,故卸载 Apache
        apt-get remove -y apache2
    
        # 配置 MySQL 密码
        debconf-set-selections <<< "mysql-server mysql-server/root_password password ${MYSQL_ROOT_PASSWORD}"
        debconf-set-selections <<< "mysql-server mysql-server/root_password_again password ${MYSQL_ROOT_PASSWORD}"
    
        # 安装 Nginx、MySQL、Redis、Memcached、Beanstalkd、SQlite 3
        apt-get install -y nginx mysql-server redis-server memcached beanstalkd sqlite3
    
        # 「⚠️重点」将 /var/www 目录的拥有者和拥有组分别配置为 WWW_USER 和 WWW_USER_GROUP 变量的值,通常均为 www-data
        chown -R ${WWW_USER}.${WWW_USER_GROUP} /var/www/
    
        # 「⚠️重点」设置 Nginx 服务开机自启
        systemctl enable nginx.service
    }
  7. 安装 Node.js 和 Yarn

    function install_node_yarn {
        # 安装 Node.js 和 Yarn
        apt-get install -y nodejs yarn
        # 配置 Yarn 国内镜像源
        sudo -H -u ${WWW_USER} sh -c 'cd ~ && yarn config set registry https://registry.npm.taobao.org'
    }
  8. 安装 Composer

    function install_composer {
        # 「⚠️重点」下载 Composer 的 PHAR 文件
        wget https://dl.laravel-china.org/composer.phar -O /usr/local/bin/composer
        # 「⚠️重点」给予该文件可执行权限
        chmod +x /usr/local/bin/composer
        # 配置 Packagist 国内镜像
        sudo -H -u ${WWW_USER} sh -c  'cd ~ && composer config -g repo.packagist composer https://packagist.laravel-china.org'
    }
  9. 配置站点

    # 读入站点名(项目名)
    read -r -p "请输入项目名:" project
    
    # 确保项目名正常,若包含非法字符则报错并退出
    [[ $project =~ ^[a-zA-Z\0-9_\-\.]+$ ]] || {
        ansi -n --bold --bg-red "项目名包含非法字符"
        exit 1
    }
    
    # 读入站点域名
    read -r -p "请输入站点域名(多个域名用空格隔开):" domains
    
    # 拼接站点根目录
    project_dir="/var/www/${project}"
    
    # 输出信息,以便用户确认
    ansi -n --bold --green "域名列表:${domains}"
    ansi -n --bold --green "项目名:${project}"
    ansi -n --bold --green "项目目录:${project_dir}"
    
    # 确保用户确认后继续执行,否则退出
    read -r -p "是否确认? [y/N] " response
    case "$response" in
        [yY][eE][sS]|[yY])
            ;;
        *)
            ansi -n --bold --bg-red "用户取消"
            exit 1
            ;;
    esac
    
    # 「⚠️重点」读入 Nginx 配置模板,并替换站点名、域名、根目录
    # 随后写入实际配置文件 /etc/nginx/sites-available/<站点名>.conf
    cat ${CURRENT_DIR}/nginx_site_conf.tpl |
        sed "s|{{domains}}|${domains}|g" |
        sed "s|{{project}}|${project}|g" |
        sed "s|{{project_dir}}|${project_dir}|g" > /etc/nginx/sites-available/${project}.conf
    
    # 创建配置文件软链接,类似快捷方式
    ln -sf /etc/nginx/sites-available/${project}.conf /etc/nginx/sites-enabled/${project}.conf
    
    # 输出
    ansi -n --bold --green "配置文件创建成功";
    
    # 创建站点根目录,并分别配置目录自身的拥有者和拥有组为 WWW_USER 与 WWW_USER_GROUP 变量的值
    mkdir -p ${project_dir} && chown -R ${WWW_USER}.${WWW_USER_GROUP} ${project_dir}
    
    # 重启 Nginx 服务
    systemctl restart nginx.service
    
    # 输出
    ansi -n --bold --green "Nginx 重启成功";

以上便是整个脚本的核心代码;有些没看懂?没关系。你现在要做的是了解流程 —— 从干干净净的服务器到完整的运行环境,需要做什么?

因此,将以上代码简化、总结,可归纳为:

  1. 初始化系统并安装基础软件包
  2. 安装 Nginx
  3. 安装 PHP-FPM
  4. 安装 Git 和 Composer
  5. 安装其它可选软件
  6. 配置 Nginx 站点

依旧存在的问题

虽然一键脚本能够帮我们完成大多数环境安装与配置,相比 Web 面板在一定程度上更加安全,但它也存在着不可避免的问题:

  • 维护困难 —— 需编写大量判断语句,调试较为困难,且极易出现不兼容。
  • 无法定制 —— 难以处理环境定制化需求(例如测试环境与生产环境的不同配置),除非 Fork 修改源代码仓库并修改脚本。
  • 黑盒操作 —— 在脚本运行过程中,它做了什么?具体执行了那些命令?我们不得而知。
  • 安全堪忧 —— 市面上几乎所有一键脚本均强行要求根用户权限(最高管理员),有潜在安全隐患。
  • ...

在随后的课程中,你将会切身感受到 —— 无论是编写得多么完善、在多少台服务器上测试通过的一键脚本,都会有它十分受限的场景。实际上,目前已经存在不少方案能够完美地解决这些问题;不过,在开始讲解之前,我将先带领大家按照刚刚归纳的步骤,一步一步地进行手动部署,在这个过程中,希望你能够:

  • 巩固安装、配置环境的流程思路
  • 把流程转化为具体命令,在脑海中形成大概的印象

所谓「无他,唯手熟尔」,勤动手、切勿畏惧报错。如果你身处墙外,Google 和 StackOverflow 是你的好帮手;若是身处墙内,LearnKu(Laravel-China)也是不错的选择。善用搜索引擎和社区,或是在本课程内提问,我将尽我所能答疑解惑。

准备好开始探险吧!

记住 —— 熟能生巧

拓展:Cloud-Init

你是否听说过 Cloud-Init?它的原理便是在服务器启动(首次运行)时,载入一段用户自定义的脚本并执行,与一键脚本类似。但其运行过程完全无法调试,若出现问题只能在服务器启动后查看文件日志寻找线索,实在是万分痛苦。因此,本课程将不讲解采用 Cloud-Init 的部署方案,使用 Ansible 代替,敬请关注后续章节。