選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
10 分鐘閱讀時間 (1973 個字)

Ansible # 16 - Playbook [3]

shutterstock_198004562
  • 前一篇透過 Ansible 部署了一個 Node.js 的 Application,而這篇的範圍會更大更廣,小心別暈車啊!

  • 此篇的重點會是在一個 Ubuntu VM 上建立 LAMP 架構跑 Drupal

    • 什麼是 LAMP
      • 這是一個比較早期曾經很夯的架構
      • L 代表 Linux,就是作業系統為 Linux (我們會用 Ubuntu 20.04)
      • A 代表 Apache,作為 Web Server
      • M 代表 MySQL,在當時還是開源的資料庫
      • P 代表 PHP,地表最強語言你敢嘴(X)
    • 什麼是 Drupal
      • 比較 hardcore 的開發者應該不太會用這種東西
      • 它跟 Wordpress 一樣是一種 CMS(Content Management System)
      • 不需要太多的技術專業知識就可以架起一個站,像是部落格,並且可以維護管理其內容
  • 稍微了解一下背景後就正式開始吧

    • 首先先來講一下如何讓我們的主要 playbook 看起來更簡潔

      • 可以透過 vars_files,把需要的變數抽出去
      • 善用 pre_taskspost_tasks主要 Task 的事前的處理與事後的善後
      • 可以透過 handlers 的定義,搭配其他 task 的 notify,在不同群的 Task 完成且成功後處理某件事(e.g. 改了設定要重開 Server 才會吃到新設定)
    • 以上提到的東西,都可以在個別的檔案中定義,再 import 到主要的 playbook 中

      • 但此篇會先保持原本的大 playbook 樣貌,後續再作說明有哪些方法可以更有組織地維護
      • 預設 Ansible 在 Task 失敗的時候就會停止執行整個 playbook,如果想避免這樣的事發生,可以多加 --force-handlers
    • 在進入下一節前,我們先把上述的東西寫到 playbook.yml 裡

        ---
        - hosts: all
      
          vars_files:
            - vars.yml
      
          pre_tasks:
            - name: Update apt cache if needed.
              apt: update_cache=yes cache_valid_time=3600
      
          handlers:
            - name: restart apache
              service: name=apache2 state=restarted
      • 簡單說明一下,hosts 大家都看過了,主要是記錄 group 與其他相關的變數,正式的名稱叫 inventory
      • vars_files 就是把參數抽出去獨立的一至多個檔案,而裡面定義變數的方式都是一樣的
      • pre_tasks 就是在進入主要工作前要做的,比方說先更新 yum/apt/brew 的 cache
      • handlers 就是某些工作群完成時的處理機制,像是重開apache/nginx/docker...等
    • 好的,既然我們要在 LAMP 上建立服務,那首先要建立的就是 LAMP 本身,這是比較簡單的部份,但流程還是不簡單,YAML 檔如下所示:

        tasks:
          - name: Get software for apt repository management.
            apt: name={{ item }} state=present
            with_items:
              - python3-apt
              - python3-pycurl
      
          - name: Add ondrej repository for later versions of PHP.
            apt_repository: repo='ppa:ondrej/php' update_cache=yes
      
          - name: "Install Apache, MySQL, PHP, and other dependencies."
            apt: state=present
            name:
              name:
                - acl
                - git
                - curl
                - unzip
                - sendmail
                - apache2
                - php7.4-common
                - php7.4-cli
                - php7.4-dev
                - php7.4-gd
                - php7.4-curl
                - php7.4-json
                - php7.4-opcache
                - php7.4-xml
                - php7.4-mbstring
                - php7.4-pdo
                - php7.4-mysql
                - php-apcu
                - libpcre3-dev
                - libapache2-mod-php7.4
                - python3-mysqldb
                - mysql-server
      
          - name: Disable the firewall (since this is for local dev only).
            service: name=ufw state=stopped
      
          - name: "Start Apache, MySQL, and PHP."
            service: "name={{ item }} state=started enabled=yes"
            with_items:
              - apache2
              - mysql
      • 我們安裝了一些 helper libraries 來幫助 python 更有效率的管理 apt。像是 python3-apt, python3-pycurl 是為了 apt_repository 可以運作
      • 接著就是安裝了一堆為了 Drupal 可以跑的 PHP 相關套件,以及 mysql
      • 暫時關閉了防火牆,畢竟只是要先測試,在正式環境應該是要開通80, 443, 22..等需要的 port
      • 最後我們開啟了所有的服務,並確保它的狀態是開啟的
    • 裝好了之後當然要開始針對細部作調整了

      • 首先是 Apache Server,我們要針對它作mod_rewrite 的設定,它是什麼可以參考連結的詳細說明,大致上就是作 url mapping

      • 除此之外我們要設定 VirtualHost,讓 Apache 知道網站的根目錄在哪兒

      • YAML 的內容如下:

          - name: Enable Apache rewrite module (required for Drupal).
            apache2_module: name=rewrite state=present
            notify: restart apache
        
          - name: Add Apache virtualhost for Drupal 8 development.
            template: 
              src: "templates/drupal.dev.conf.j2"
              dest: "/etc/apache2/sites-available/{{ domain }}.dev.conf"
              owner: root
              group: root
              mode: 0644
              notify: restart apache
        
          - name: Enable the Drupal site.
            command: >
              a2ensite {{ domain }}.test
              creates=/etc/apache2/sites-enabled/{{ domain }}.test.conf
            notify: restart apache
        
          - name: Disable the default site.
            command: >
              a2dissite 000-default
              removes=/etc/apache2/sites-enabled/000-default.conf
            notify: restart apache
        • 首先啟動了apache 的 rewrite 機制,將所有需要的模組都啟動了

        • 接著設定了 VirtualHost,特別留意這邊用到了一個叫 jinja2 template 的東西,它作用就跟 Freemarker 很相似,都是填值入坑的一種範本的技術,範本的內容如是:

            <VirtualHost *:80>
              ServerAdmin webmaster@localhost
              ServerName {{ domain }}.test
              ServerAlias www.{{ domain }}.test
              DocumentRoot {{ drupal_core_path }}/web
              <Directory "{{ drupal_core_path }}/web">
                Options FollowSymLinks Indexes
                AllowOverride All
              </Directory>
            </VirtualHost>           
          • 那些 {{ }} 內的東西,都會透過 Ansible 的 template module 從 vars.yml 裡取值並取代之

          • 所以我們要在 vars.yml 裡加上以下的值

              ---
              # The path where Drupal will be downloaded and installed.
              drupal_core_path: "/var/www/drupal"
            
              # The resulting domain will be [domain].test (with .test appended).
              domain: "drupal"
            
              # Your Drupal site name.
              drupal_site_name: "Drupal Test"
        • 再來最後的兩個 task 是啟用我們設定好的 VirtualHost,並移除預設的版本

      • 接著要設定 OpCache,主要會透過 lineinfile 這個 module來處理

          - name: Adjust OpCache memory setting.
            lineinfile:
              dest: "/etc/php/7.4/apache2/conf.d/10-opcache.ini"
              regexp: "^opcache.memory_consumption"
              line: "opcache.memory_consumption = 96"
              state: present
            notify: restart apache
        • lineinfile 基本上就是確保某一行字存在與否
        • 這裡主要是為了讓 PHP 效能更好而作調整
        • lineinfile 實際的參數說明如下:
          • dest 就是我們要處理的檔案
          • regexp 就是我們要找的文字目前長怎樣,這裡主要是透過正則運算式去找
          • line 表示找到的文字應該要改成怎樣,以這邊為例就是要多加上 = "96"
          • state 就是找到這行文字應該或不應該存在,由 present/absent 定義之
          • 特別留意,如果 regexp 找不到對應的文字,line 的內容就會直接被加到 dest 內,Ansible 只會告訴我們它是 Add 或是 change 了內容
      • 接著來處理 MySQL 的部份

        • 先建立 Drupal 會用到的 database

        • 再建立 Drupal 會用到的 user

            - name: Create a MySQL database for Drupal.
              mysql_db: "db={{ domain }} state=present"
          
            - name: Create a MySQL user for Drupal.
              mysql_user:
                name: "{{ domain }}"
                password: "1234"
                priv: "{{ domain }}.*:ALL"
                host: localhost
                state: present
        • Ansible 本身有許多的 module 在處理資料庫的,像是 MySQL,postgreSQL, MongoDB, ... 等,詳情可參考連結

      • 再來要裝 Composer,一個 PHP 的套件管理

        • 因為是下載安裝,所以就直接看 yaml 吧:

            - name: Download Composer installer.
              get_url:
                url: https://getcomposer.org/installer
                dest: /tmp/composer-installer.php
                mode: 0755
          
            - name: Run Composer installer.
              command: >
                php composer-installer.php
                chdir=/tmp
                creates=/usr/local/bin/composer
            - name: Move Composer into globally-accessible location.
              shell: >
                mv /tmp/composer.phar /usr/local/bin/composer
                creates=/usr/local/bin/composer
          • 上面有幾個重點:
            • 透過 get_url module 下載 composer 的安裝檔
            • 接著就是透過 commandshell module 處理讓 Linux 知道怎麼使用這個 binary
      • 再來要安裝 Drush,Drupal 專用的 CLI

        • 因為是下載安裝,所以就直接看 yaml 內容如下:

            - name: Ensure Drupal directory exists.
              file:
                path: "{{ drupal_core_path }}"
                state: directory
                owner: www-data
                group: www-data
          
            - name: Check if Drupal project already exists.
              stat:
                path: "{{ drupal_core_path }}/composer.json"
              register: drupal_composer_json
          
            - name: Create Drupal project.
              composer:
                command: create-project
                arguments: drupal/recommended-project "{{ drupal_core_path }}"
                working_dir: "{{ drupal_core_path }}"
                no_dev: true
              become_user: www-data
              when: not drupal_composer_json.stat.exists
          
            - name: Add drush to the Drupal site with Composer.
              composer:
                command: require
                arguments: drush/drush:10.*
                working_dir: "{{ drupal_core_path }}"
              become_user: www-data
              when: not drupal_composer_json.stat.exists
      • Composer 跟 Drush 都準備好了,那就要來安裝 Drupal 了

        • yaml 如下:
            - name: Install Drupal.
              command: >
                vendor/bin/drush si -y --site-name="{{ drupal_site_name }}"
                --account-name=admin
                --account-pass=admin
                --db-url=mysql://{{ domain }}:1234@localhost/{{ domain }}
                --root={{ drupal_core_path }}/web
                chdir={{ drupal_core_path }}
                creates={{ drupal_core_path }}/web/sites/default/settings.php
              notify: restart apache
              become_user: www-data
          • 這段主要用 Drush 這個 cli 安裝 drupal
    • 整個目錄架構如下圖:

      • Vagrantfile 用來起 Ubuntu 20.04,並設定 Ansible 當 provision

        # -*- mode: ruby -*-
        # vi: set ft=ruby :
        
        VAGRANTFILE_API_VERSION = "2"
        
        Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
        config.vm.box = "geerlingguy/ubuntu2004"
        config.vm.network :private_network, ip: "192.168.88.8"
        config.vm.hostname = "drupal.test"
        config.ssh.insert_key = false
        
        config.vm.provider :virtualbox do |v|
          v.memory = 2048
        end
        
        # Ansible provisioning.
        config.vm.provision "ansible" do |ansible|
          ansible.playbook = "provisioning/playbook.yml"
        end
        end
      • provisioning 裡面放著

        • playbook.yml 裡面定義所有的任務
        • vars.yml 裡面定義所有會用到的變數
        • templates 裡面放著搭配 Ansible template 這個 module 的 jinja2 template
      • 最後再一個 vagrant up,就可以起一個 Ubuntu VM,裡面跑著 Drupal 的 Web Application 了

  • 這篇真的是又臭又長呢~

    • 沒錯…就是故意的,畢竟沒有什麼是可以一步到位的
    • 之後會針對 playbook 再多補充及複習相關的概念,再來講解如何一步步讓這個超大 playbook 變得可共用,好維護
    • 如果可以的話,各位也可以嘗試將自己平時開發需要的環境透過 Ansible 建起來,或是透過 Ansible 將測試機的環境建構起來,之後如果發生什麼意外(e.g. 硬碟壞軌),至少還有一個 playbook 可以省你很多時間呢!
AspNetBoilerplate(ABP) - 外部登入
Ansible # 15 - Playbook [2]

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/03, 週五

Captcha 圖像