Mount GCP storage 給 apache php 存取

遇到的情況是要在 ubuntu 機器上 mount 非 public access 的 gcp storage bucket,然後要給 php web api 做讀寫。

比較正常的解決方式應該是用 google cloud storage api for PHP(https://googleapis.github.io/google-cloud-php/#/docs/cloud-storage/v1.24.1/storage/storageclient 使用說明 & https://github.com/googleapis/google-cloud-php-storage github),但因為要趕著上線並把原本儲存在local disk 改去 gcp cloud storage去,所以趕著做就先用 mount bucket 的方式去做讀寫。

先安裝 gcsfuse

安裝說明可以直接看 https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/docs/installing.md

mount with gcsfuse

可以看 https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/docs/mounting.md,但是要注意的是單純地做 mount 則路徑權限會跟著 mount 的帳號。所以,假設用 root mount,那麼通常 ubuntu 上跑 apache2.4 的 www-data 這跟身分就不能直接存取,就算把 www-data 加入 sudo 身分,也不能使用像是 php 中的 filesize() 這樣的函式。

說明裏頭有提到可以用 credential key file (json format)的方式,另外這篇文章也有提到,不過因為手上這台機器已經有做過 gcloud auth login,所以沒有用這樣的方式。

mount as www-data identity

但很詭異的是照著文件最底下(這邊)所寫的,將 mount 寫在 /etc/fstab 卻一直有問題。所以我改成寫在 crontab 裡頭,但一樣要先確認 www-data 的 id。

$ id --help
Usage: id [OPTION]... [USER]
Print user and group information for the specified USER,
or (when USER omitted) for the current user.

  -a             ignore, for compatibility with other versions
  -Z, --context  print only the security context of the process
  -g, --group    print only the effective group ID
  -G, --groups   print all group IDs
  -n, --name     print a name instead of a number, for -ugG
  -r, --real     print the real ID instead of the effective ID, with -ugG
  -u, --user     print only the effective user ID
  -z, --zero     delimit entries with NUL characters, not whitespace;
                   not permitted in default format
      --help     display this help and exit
      --version  output version information and exit

Without any OPTION, print some useful set of identified information.

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
Report id translation bugs to <http://translationproject.org/team/>
Full documentation at: <http://www.gnu.org/software/coreutils/id>
or available locally via: info '(coreutils) id invocation'
$ id -g www-data
33
$ id -u www-data
33

然後便是在 crontab 中加入 @reboot 去做 mount

$ crontab  -l
@reboot gcsfuse --uid 33 --gid 33 --implicit-dirs -o allow_other -file-mode=660 -dir-mode=770 BUCKET-NAME  /PATH/TO/MOUNT/

但終究比較好的方式是乖乖用 google cloud storage api, 這樣就只要單純 deploy 程式跟 credential key file 就解決,不用弄這些設定。