輕鬆部署 Laravel 應用 | 《03. 探尋一鍵指令碼》

Wi1dcard發表於2019-03-04

:clap: 本系列持續更新中,歡迎關注:https://github.com/wi1dcard/laravel-deploy...

由於課程上下文關聯比較緊密,在開始前請先閱讀 本文

你的支援是我寫作的動力;關注我的客官們,請在右上角點個贊,將會讓文章在首頁展示,幫助更多人。

感謝 :clap: !

一鍵指令碼里都做了什麼?相信不少開發者有過這樣的疑問,在完全地熟悉 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 代替,敬請關注後續章節。

我感謝自己平凡,敢愛敢恨沒負擔。
我感謝自己不凡,可愛可恨都包攬。

相關文章