從零開始的Laravel生活(部署篇)

前言

上次把專案寫完,直到最近才終於能碰到要部屬的機子。這次要部署的主機是學校的 VM,作業系統為 Ubuntu 20.04.3,算是很常見的 Linux 環境。本篇內容記錄程式部署的過程和主機的一些基本設定。

正文

主機環境

基本的 zsh 還有一些雜項另外一位網管幫忙做完了,實際上我有做的只有下面幾項。

時區調整

先檢查一下伺服器現在的時區

1
timedatectl

伺服器一開始是標準時區(+0),要調整時區可以直接用內建的工具。

1
sudo tzselect

過程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Please identify a location so that time zone rules can be set correctly.
Please select a continent, ocean, "coord", or "TZ".
1) Africa
2) Americas
3) Antarctica
4) Asia
5) Atlantic Ocean
6) Australia
7) Europe
8) Indian Ocean
9) Pacific Ocean
10) coord - I want to use geographical coordinates.
11) TZ - I want to specify the timezone using the Posix TZ format.
#? 4
Please select a country whose clocks agree with yours.
1) Afghanistan 18) Israel 35) Palestine
2) Armenia 19) Japan 36) Philippines
3) Azerbaijan 20) Jordan 37) Qatar
4) Bahrain 21) Kazakhstan 38) Russia
5) Bangladesh 22) Korea (North) 39) Saudi Arabia
6) Bhutan 23) Korea (South) 40) Singapore
7) Brunei 24) Kuwait 41) Sri Lanka
8) Cambodia 25) Kyrgyzstan 42) Syria
9) China 26) Laos 43) Taiwan
10) Cyprus 27) Lebanon 44) Tajikistan
11) East Timor 28) Macau 45) Thailand
12) Georgia 29) Malaysia 46) Turkmenistan
13) Hong Kong 30) Mongolia 47) United Arab Emirates
14) India 31) Myanmar (Burma) 48) Uzbekistan
15) Indonesia 32) Nepal 49) Vietnam
16) Iran 33) Oman 50) Yemen
17) Iraq 34) Pakistan
#? 43

The following information has been given:

Taiwan

Therefore TZ='Asia/Taipei' will be used.
Selected time is now: Thu Sep 9 13:03:40 CST 2021.
Universal Time is now: Thu Sep 9 05:03:40 UTC 2021.
Is the above information OK?
1) Yes
2) No
#? Yes
Please enter a number in range.
#? 1

You can make this change permanent for yourself by appending the line
TZ='Asia/Taipei'; export TZ
to the file '.profile' in your home directory; then log out and log in again.

Here is that TZ value again, this time on standard output so that you
can use the /usr/bin/tzselect command in shell scripts:
Asia/Taipei

再次檢查時區

1
timedatectl

發現沒有變動,所以只好換個方法,接下來嘗試直接改動/etc/localtime的連結位置來更改時區

1
sudo ln -sf /usr/share/zoneinfo/Asia/Taipei /etc/localtime

確認一下結果

1
2
3
4
5
6
7
               Local time: Thu 2021-09-09 13:09:17 CST
Universal time: Thu 2021-09-09 05:09:17 UTC
RTC time: Thu 2021-09-09 05:09:17
Time zone: Asia/Taipei (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

時區改動了

timedatectl 可以拿來改時區

1
2
3
4
timedatectl list-timezones # 找你的時區
sudo timedatectl set-timezone <time_zone>
# Example
sudo timedatectl set-timezone Asia/Taipei

ssh 登入限制

由於管理員們都是使用公鑰登入,為了安全考量決定把 ssh 的密碼登入關掉。

1
sudo nano /etc/ssh/sshd_config

sshd_config

1
2
3
4
5
6
7
8
9
10
# Authentication:

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

PubkeyAuthentication yes
PasswordAuthentication no

PubkeyAuthentication取消註解再把PasswordAuthentication no補進去就可以了。

可以再加個Fail2ban效果拔群

Docker 安裝

Docker Engine

直接照著官網說明走,把 docker engine 裝起來

之後要給使用者帳號 docker 群組的權限

1
sudo usermod -aG docker <user>

之後 docker 應該就能正常跑起來,可以打下面指令試試看

1
docker version

如果有 Permission Denied 之類的錯誤訊息應該就是沒把使用者加進 docker 組

Docker Compose

一樣照官網的說明操作

用 curl 載下來以後給執行權限丟到有在 PATH 裡面的目錄就可以了,基本上就是個執行檔。

部署前測試

下載專案檔

直接採用 Git 可以快速地把專案的程式碼複製到主機上來,與此同時要小心 GitLeak,如果 web server 的設定正確的話應該就不用擔心。

安裝 Laravel Package

先把 Docker 服務架起來

1
docker-compose up -d

要在專案目錄下用才抓的到docker-compose.yml

1
2
3
4
5
6
7
docker attach app # 這裡寫你container的名稱
composer install # 把php的套件裝完
npm install # node的套件
cp .env.example .env # 把env檔案建起來,待會還要進去設定
php artisan key:generate # 產生一個加密用的key,Laravel會用到
php artisan optimize # 把Laravel的快取清掉再重建
php artisan migrate --seed # 跑migrate讓他把資料庫table建起來

.env的設定調整完後,前置作業應該做完了,但是肯定還有 Bug 吧?

Laravel Permission Denied

果不其然,一連上伺服器就跳 500,只好把 debug 打開看,結果是 Laravel 沒有寫入檔案的權限。

原因來自 Docker 預設會用 root 來對 container 裡面做操作,因此在 Docker 掛載完 volume 後,整個 volume 都變成 root 才能操作。要解決只要在docker-compose.yml裡面指定好使用者就可以了。

1
2
3
4
5
6
7
8
9
10
app:
build:
context: ./
dockerfile: app.dockerfile
user: "www-data:www-data"
working_dir: /var/www
volumes:
- ./:/var/www
environment:
- "DB_PORT=3306"

這樣一進到 container 就會用 www-data 來做操作,應該可以避免掉 Laravel 無法更動檔案的問題。

如果還是出現 Permission Denied 的狀況,就要手動設定資料夾內的權限。可嘗試sudo chown -R www-data:www-data /path,如果此操作反而導致 Docker 沒辦法讀取資料夾內的內容一樣可以透過手動調整權限解決

部署

Laravel 性能優化

測試沒問題後發現網站實在是跑很慢,甚至要等個一秒才會有回應,可以嘗試以下的性能優化方法。

調整設定檔

1
2
APP_ENV=production
APP_DEBUG=false

調整這兩項

利用快取

1
2
3
4
php artisan optimize # 把路由還有一些快取清掉再重建
php artisan config:cache # 把config快取起來
php artisan route:cache # 把路由快取起來
composer dump-autoload --optimize # 生成classmap

Opcache

這部分我沒有使用到,有興趣的人可以再另外搜尋。

結果

速度提升非常明顯,client 從送出到收到回覆簡短到 100 多 ms

Database 存取控制

預設上 MariaDB 會把 root 的遠端登入開啟,如果要關閉的話可以從環境變數設定

1
2
environment:
- "MARIADB_ROOT_HOST=127.0.0.1"

不過就算設定了,別人還是可以用其他帳號登入,所以最好方式就是不要開 port,可以省下麻煩。反正就算不把 port 橋接到主機上,container 之間還是可以互相連線。

最後 database 在 docker-compose 裡面長這樣

1
2
3
4
5
6
7
8
9
10
11
database:
image: mariadb:latest
restart: always
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=tree"
- "MYSQL_USER=tree"
- "MYSQL_PASSWORD=secret"
- "MARIADB_ROOT_PASSWORD=secret"
- "MARIADB_ROOT_HOST=127.0.0.1"

切掉外部連線一勞永逸,從外部就沒辦法再登入 DB 了。

結語

這次部署其實做的滿隨便的,現在系統還沒正式上線,所以應該還會再做一些調整,如果有任何變更我也會更新上來。