Laradock 學習筆記

# 前言

Laradock 使用筆記


# 安裝


# Laradock 架構

# 已經有一個專案

參考 官方文件


# 還沒有專案

參考 官方文件


# 多專案

可參考 官方文件
下面主要針對多專案來解說, 需求是

  • 一個 Laradock 資料夾
  • N 個專案
  • 可以使用不同的 PHP 版本
  • 可以使用不同類型或版本的 DB (多專案若使用同版本 DB, 共用一個 connection)
  • 可使用 PHP Unit test
  • 支援 PHPStorm unit test 功能
  • 支援 APC cache
  • 可在 container 內呼叫自己, 而非 host (用於 testing)

# Laradock 位置

位置隨意, 想放哪都可以

# env 檔設定

預設不會有 .env file, 要 copy Laradock 資料夾內的 env-example to .env

copy env-example .env

接下來, 為了實現多專案, 所以我們建一個資料夾, 裡面專放各個專案的 .env, 即每個不同專案的環境資訊, 這個資料夾放哪都行
接著, 在該資料夾內, 除了從預設 env-example 複製過來的 .env, 為了區別預設環境跟各個專案獨有的環境設定, 我們新增一個 .env.custom, 內容如下

#################### 以下為客製化選項#####################

# 該專案絕對路徑, 該路徑下檔案會被映射到 workspace 內
APP_CODE_PATH_HOST=/path/to/yourProject
# 資料庫資料的持久化位置, 設哪都行, 如果不同專案使用不同版本的資料庫, 但卻存在同一個位置, 那會有相容性問題, 因此只要是不同類型不同版本的資料庫, 都應該獨立設一個位置
DATA_PATH_HOST=/path/to/yourDataLocation
PHP_VERSION=7.4
MYSQL_VERSION=8.0
# 僅有第一次建立 DATA_PATH_HOST 會自動建立, 如果有第二個專案使用的資料庫版本跟之前的一樣, 那此選項無作用
MYSQL_DATABASE=yourDBName
# 映射到 host 的 port, 所以本機可以通過此 port 連接到 DB
MYSQL_PORT=33080
# 專案名稱, 會顯示於 container prefix
COMPOSE_PROJECT_NAME=yourProjectName
# Nginx 的 log 映射到 host 的位置, 可設定在各專案放 .env 資料夾中
NGINX_HOST_LOG_PATH=/path/to/nginxHostLogLocation
# 不確定會不會用到, 但有沒裝而爆錯的經驗, 就全裝了
WORKSPACE_INSTALL_MYSQL_CLIENT=true
PHP_FPM_INSTALL_MYSQL_CLIENT=true
PHP_WORKER_INSTALL_MYSQL_CLIENT=true
# 這邊為 build container 時預設會執行的 MySQL query, 可用於建立資料庫, 但只有第一次有效, 同 MYSQL_DATABASE
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-8.0-initdb.d
# 如果有用到 APC, 設為 true
PHP_FPM_INSTALL_APCU=true
# 若要使用 PHPSTORM 的 unit test 或 debug 功能, 設為 true
WORKSPACE_INSTALL_WORKSPACE_SSH=true

當設定好 .env.custom 後, 可將其內容 append 到預設的 .env, 這樣比較清楚到底改了什麼

cat .env.custom >> .env

# MySQL 設定

# 若擔心 collation 問題, 可設定 my.cnf, 基本上不需要

  • my.cnf (與 create.sql 擇一即可)

    vim laradock/mysql/my.cnf
  • 加入以下設定

    [client]
    default-character-set=utf8

    [mysql]
    default-character-set=utf8


    [mysqld]
    collation-server = utf8_unicode_ci
    init-connect='SET NAMES utf8'
    character-set-server = utf8

# 除了 my.chf, 也可使用 create.sql, 擇一即可

  • 修改

    vim laradock/mysql/docker-entrypoint-initdb.d/createdb.sql
  • 內容

    SET CHARACTER_SET_CLIENT=utf8mb4;
    SET CHARACTER_SET_RESULTS=utf8mb4;
    SET CHARACTER_SET_database= utf8;
    SET COLLATION_CONNECTION=utf8_unicode_ci;

# 驗證方式

因為 PHP 7.3 之前的版本並不支援 MySQL 8 的密碼驗證方式, 可參考, 若非得使用舊版本 PHP 新版本 MySQL 的組合的話, 如下設定

  • 修改 my.cnf

    vim laradock/mysql/my.cnf
  • 內容

    [mysqld]
    default_authentication_plugin= mysql_native_password
  • 如修改無法生效, 需把 MySQL 的檔案刪除重建, 這會把該版本資料庫所有資料都刪除, 慎用, 目標為 .env 中設定的 DATA_PATH_HOST

    rm -rf /path/to/yourDataLocation

# 建立 Database, 只有該版本第一次建立有效

  • 複製範例檔

    cp laradock/mysql/docker-entrypoint-initdb.d/createdb.sql.example laradock/mysql/docker-entrypoint-initdb.d/createdb.sql
  • 批量新增資料庫
    uncomment 以下的設定檔, 並將 dev_db_1 … 換成自己需要的資料庫名字

    #CREATE DATABASE IF NOT EXISTS `dev_db_1` COLLATE 'utf8_general_ci' ;
    #GRANT ALL ON `dev_db_1`.* TO 'default'@'%' ;

    #CREATE DATABASE IF NOT EXISTS `dev_db_2` COLLATE 'utf8_general_ci' ;
    #GRANT ALL ON `dev_db_2`.* TO 'default'@'%' ;

    #CREATE DATABASE IF NOT EXISTS `dev_db_3` COLLATE 'utf8_general_ci' ;
    #GRANT ALL ON `dev_db_3`.* TO 'default'@'%' ;

# 更改帳號密碼, 只有該版本第一次建立有效

vim laradock/.env

搜尋 MySQL 並將 default user 的密碼以及 root 的密碼更改


# 專案配置

# .env

  • 修改專案的 .env, 非 Laradock .env

    vim yourProject/.env
  • 更改 DB_HOST 為 mysql

  • 更改 DB_DATABASE 設為該專案使用的資料庫, 如果使用的資料庫版本之前已經有建立過, 只是沒有該資料庫, 那 build 過程是不會主動建立的, 要手動連接到資料庫建立, 方可使用

  • 更改 DB_USERNAME 為 default (可自定義)

  • 更改 DB_PASSWORD


# 修改 storage 權限, 預設應該是不用改

sudo chmod -R 777 storage bootstrap/cache

# Supervisor

當我們有使用 queue 或是 scheduler 的功能時, 會需要在背景起一個 process 用來監聽 queue job, 這時便需要使用程序管理器, 像是 supervisor 或 pm2
Laradock 已內建 supervisor 可以使用, 相當方便。


# 用法

  1. 切換到 Laradock/php-worker 目錄中, 可依據需求修改 Dockerfile 以及 supervisord.conf, 若無需求不需修改
  2. 建立 config 檔, cp *.conf.example *.conf
  3. 啟動 docker-compose up -d php-worker

# 設置 NGINX

如果是本地開發的話, 基本上預設即可, 若要用於 production, 需設定相對應 server name

# 重導 HTTP 到 HTTPS
server {
listen 80;
listen [::]:80;

server_name yourDomainName;
return https://yourDomainName;
}

server {
# For https
listen 443 ssl;
# listen [::]:443 ssl ipv6only=on;
# 這個資料夾預設會跟 host 的 laradock/nginx/ssl/ 資料夾同步, 所以在外面放入正確的 SSL 憑證即可啟動 HTTPS
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;

server_name yourDomainName;
# 當使用多專案模式時, /var/www 會與 laradock 同層資料夾同步, 所以與 laradock 資料夾同層的專案都會被同步到這個資料夾內
root /var/www/yourProjectName/public;
index index.php index.html index.htm;

location / {
try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass php-upstream;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fixes timeouts
fastcgi_read_timeout 600;
include fastcgi_params;
}

location ~ /\.ht {
deny all;
}

location /.well-known/acme-challenge/ {
root /var/www/letsencrypt/;
log_not_found off;
}
}

# network alias 修改

如果有跑測試, 可能會需要通過 guzzle 呼叫一些內部才可呼叫的 API, 例如清除 apc cache, 因為在 container 內的 curl localhost 會被指到 host machine 的 localhost, 這樣就無法將 request 導向正確的地方
所以必須要在 docker-compose.yml file 做一些修改, 如下, 之後只要在 APP 內呼叫該 domain, 那就會映射到 container 的 localhost

### NGINX Server ###
# ... 省略 ...
networks:
frontend:
aliases:
- project.a
- project.b
backend:
aliases:
- project.a
- project.b
# ... 省略 ...

# 啟動 Laradock

啟動 Laradock 時, 我們可根據不同的 .env file 來啟動適用於不同專案的 Laradock 環境, 可將下面的冗長指令設定成 alias, 即可透過不同的 alias 來管理不同專案的 Laradock 環境

# build

完成一切設定後, 重新 build Laradock, 如果 MySQL connection 已存在, 可以不需重新 build, 如果沒有更動到預設設定的, 也不需 build
這邊需針對各個專案來指定 .env

docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv build --parallel --no-cache workspace mysql php-fpm nginx redis php-worker

# up

結束 build 後, 就可以 up Laradock 環境

docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv up -d workspace mysql php-fpm nginx redis php-worker

# down

若要刪除環境, 可使用 down

docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv down

# down

若要 stop container, 但不刪除 container, 通常專案之間切換環境並不需要刪除 container, stop 就行 (主要避免 workspace 與 nginx port 衝突而已)

docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv stop workspace mysql php-fpm nginx redis php-worker

# 執行專案前設置

務必要設定好 .env 中的 MySQL_HOST, 以及 Redis_HOST, 都要改成 mysql 以及 redis, 因為 Laravel .env 中預設的 host 位置為 host machine 的通常環境, 但在 container 中, 不同的 container 處於同一個 network, 但並不處於同一個 node, 而 Laradock 是將不同的 container 服務 alias 成 domain name, 所以 mysql 即代表 mysql container 的 IP 位置


# Laradock 環境下的 artisan 以及 composer

試想, 如果你的機器非常乾淨, 只裝了用來 pull Laradock 的 Git, 其他什麼都沒裝, 那你電腦中自然也不會有 composer, php, 所以要執行這些 command 就需要透過 docker

docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv exec workspace php artisan key:generate
docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv exec workspace php artisan migrate
docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv exec workspace php artisan db:seed
docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv exec workspace php artisan test
docker-compose -f /path/to/yoruLaradockLocation/docker.compose.yml --env-file /path/to/yourProjectEnv exec workspace composer install -d /path/to/projectLocationInWorkspace

# Unit test 資料庫

如果有使用到 TEST, 記得到資料庫中建立一個 for testing 的資料庫, 然後在 .env.test 中設置相對應的參數, 當然, 我們都是使用 container 中的資源, 所以 host, password, user 那些務必都要改成 DB container 的參數


# APC cache

Laradock 只提供了 PHP-FPM 中安裝 APC driver, 但並不支援 workspace 安裝 APC driver, 所以當跑測試時, 測試跑的是 CLI 環境, 並不透過 PHP-FPM, 因此如果有使用到 APC Cache 功能的地方就會噴錯, 因此我們必須手動到 workspace 中安裝 APC Cache

apt update && apt install php-apcu

# PHPStorm

PHPStorm 預設 testing configuration 是使用 Local 的 PHP Interpreter, 但我們 host machine 並沒有安裝 PHP, 只有 Laradock, 再者, 我們會需要 PHPStorm 是在 workspace container 中下達運行, 這樣才會使用到相對應的 DB

# SSH

  • 先到 PHPStorm 的 Preference -> Tools -> SSH Configurations, 完成以下設定, 可參考 官網

    # PHP Interpreter

  • 接著到 Preference -> Languages & Framework -> PHP 頁面中, 設定 CLI Interpreter, 選取 ..., 如下設定

# PHP Testing Configuration

  • 接著到 Preference -> Languages & Framework -> PHP -> Test Frameworks 設定 CLI Interpreter, composer autoload, phpunit.xml

  • 完成以上設定後, 應該就可以使用 testing 功能, 我的 short cut 是 shift + ctrl + r


# Jenkins

# 設定

簡易個人 side project 用的 CD 可參考 這篇文章


Shell Script

  • 從容器連到欲部署的 Server
    ssh -i /var/jenkins_home/yourDeployKey root@yourServerIP \
    "cd /yourProjectLocation/ && \\
    git reset @^ --hard && git pull \\
    && cd /laradockProjectLocation/ \\
    && /usr/bin/docker-compose exec -T --user=laradock workspace php /var/www/yourProjectName/artisan migrate --force \\
    && /usr/bin/docker-compose exec -T --user=laradock workspace composer install -d /var/www/yourProjectName \\
    && /usr/bin/docker-compose exec -T --user=laradock workspace php /var/www/yourProjectName/artisan queue:restart \\
    && /usr/bin/docker-compose exec -T --user=laradock workspace php /var/www/yourProjectName/artisan db:seed"

# Add Swap Space

當部署的機器 Memory 較低時, 常常會把 RAM 耗光, 這時我們可以通過切割一部分沒用到的硬碟給 RAM


  • 作業系統
    ubuntu 18.04

  • 確認目前 swap 大小, 如果沒有輸出, 代表目前 server 沒有劃分這一塊, 可以加了

    sudo swapon --show
  • 建立 Swap 檔案

    • fallocate: 切割硬碟給檔案
    • -l: length, 檔案大小
    • /swapfile: 檔案
      sudo fallocate -l 1G /swapfile
  • 設定正確的權限

    sudo chmod 600 /swapfile
  • 設定 Swap Space

    • mkswap: 建立 swap 區域, 可以是 disk partition, 也可以是一個檔案
      sudo mkswap /swapfile
  • 輸出:

    Output
    Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
    no label, UUID=f59595fb-754b-47ae-af6b-8dd6e98654d8
  • 啟用 Swap Space

    sudo swapon /swapfile
  • 確認 swap 是否已可被使用

    sudo swapon --show
  • 輸出

    Output
    NAME TYPE SIZE USED PRIO
    /swapfile file 1024M 0B -2
  • 確認可用使用量

    free -h
  • 輸出

    Output
    total used free shared buff/cache available
    Mem: 581M 275M 62M 103M 243M 110M
    Swap: 1.0G 0B 1.0G
  • 使 Swap 永久有效

    sudo vim /etc/fstab
  • 增加以下代碼到檔案中

    /swapfile swap swap defaults 0 0
  • 設定 swappiness
    swappiness 為 0 時, kernel 將不會將 data 換到 disk 除非真的有必要, 值越高時 kernel 會盡可能地將 data 放到 swap, 讓 RAM 更空一點
    所以, 告訴系統盡量不要依賴 swap 可以讓系統運行的快一點

  • 查看目前的 swappiness

    cat /proc/sys/vm/swappiness
  • 輸出

    Output
    60
  • 將 swappiness 設定為 10

    sudo sysctl vm.swappiness=10
  • 輸出

    Output
    vm.swappiness = 10
  • 持久化 swappiness

    sudo vim /etc/sysctl.conf
  • 加入下面這一行

    vm.swappiness=10
  • 移除 Swap Space

    sudo swapoff -v /swapfile
  • 從 /etc/fstab 移除上面加入的代碼 /swapfile swap swap defaults 0 0

  • 最後, 刪除 swap 檔案

    sudo rm /swapfile

# 非正規設置法 (自己弄好玩的, 勿學 XD)

以下是個人配置, 旨在利用 Let’s Encrypt Certbot 自動每三個月續簽 SSL 憑證, 並自動套用到每個專案
所以會在 Host 處安裝 NGINX + CertBot, 因為自動續簽 SSL 憑證會用到 NGINX 80 port, 所以容器外的 NGINX 會監聽 80 port, 並把符合條件的請求都導向由容器直接監聽的 443 port, 所以會在容器內外都安裝 NGINX

# NGINX 配置

因為 Let’s Encrypt 在自動續簽的過程中, CertBot 會 restart NGINX, 所以 NGINX 會分成容器內跟容器外


# 容器內 NGINX

// 容器外的 NGINX 會將指定 server_name 的流量導向 443 port, 所以這邊不需監聽 80 port
server {
# For https
listen 443 ssl;
# listen [::]:443 ssl ipv6only=on;
// 這個資料夾預設會跟 host 的 laradock/nginx/ssl/ 資料夾同步, 所以在外面放入正確的 SSL 憑證即可啟動 HTTPS
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;

server_name yourDomainName;
// 當使用多專案模式時, /var/www 會與 laradock 同層資料夾同步, 所以與 laradock 資料夾同層的專案都會被同步到這個資料夾內
root /var/www/yourProjectName/public;
index index.php index.html index.htm;

location / {
try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass php-upstream;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fixes timeouts
fastcgi_read_timeout 600;
include fastcgi_params;
}

location ~ /\.ht {
deny all;
}

// 此層資料夾會跟 laradock/logs/nginx 資料夾同步, 所以需要更名為你的專案名稱, 否則要是有多專案的話, 每個專案的 log 就重疊了
error_log /var/log/nginx/yourProjectName_error.log;
access_log /var/log/nginx/yourProjectName_access.log;
}

# 容器外 NGINX

// 容器外相當簡單, 將來自 80 port 的請求導向 443 即可

server {
listen 80;
server_name *.yourDomainName;

return https://$host$request_uri;
}

# Let’s Encrypt

安裝可參考 取得 wildcard SSL 憑證


# 其他配置檔

# docker-compose.yaml

取拿掉 80 port 對應, 因為 80 port 會由容器外的 NGINX 監聽

ports:
- "${NGINX_HOST_HTTPS_PORT}:443"

# Laradock 的 .env

// 因為 80 port 沒開, 所以參數也不需設定
### NGINX #################################################

NGINX_HOST_HTTP_PORT=
NGINX_HOST_HTTPS_PORT=443
NGINX_HOST_LOG_PATH=./logs/nginx/
NGINX_SITES_PATH=./nginx/sites/
NGINX_PHP_UPSTREAM_CONTAINER=php-fpm
NGINX_PHP_UPSTREAM_PORT=9000
NGINX_SSL_PATH=./nginx/ssl/

Docker 實戰入門 <未完成>利用 Stackdriver APM 來增進網站可靠性以及排除錯誤

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×