shop_platform - 部署到 GCP (2)
監聽 80 port(後來發現其實不需要)
試著在 80 port 上開啟伺服器,但是失敗了
flora@*******:~/shop_platform$ pipenv run gunicorn "app:create_app()"
Loading .env environment variables...
[2021-10-28 13:38:45 +0000] [22652] [INFO] Starting gunicorn 20.1.0
[2021-10-28 13:38:45 +0000] [22652] [ERROR] Retrying in 1 second.
[2021-10-28 13:38:46 +0000] [22652] [ERROR] Retrying in 1 second.
[2021-10-28 13:38:47 +0000] [22652] [ERROR] Retrying in 1 second.
[2021-10-28 13:38:48 +0000] [22652] [ERROR] Retrying in 1 second.
[2021-10-28 13:38:49 +0000] [22652] [ERROR] Retrying in 1 second.
[2021-10-28 13:38:50 +0000] [22652] [ERROR] Can't connect to ('0.0.0.0', 80)
換成別的 port 就沒問題
flora@*******:~/shop_platform$ pipenv run gunicorn --bind 0.0.0.0:5000 "app:create_app()"
Loading .env environment variables...
[2021-10-28 14:00:11 +0000] [22879] [INFO] Starting gunicorn 20.1.0
[2021-10-28 14:00:11 +0000] [22879] [INFO] Listening at: http://0.0.0.0:5000 (22879)
[2021-10-28 14:00:11 +0000] [22879] [INFO] Using worker: sync
[2021-10-28 14:00:11 +0000] [22888] [INFO] Booting worker with pid: 22888
參考 Run a flask app on port 80 without sudo:
sudo apt install authbind
sudo touch /etc/authbind/byport/80
sudo chmod 777 /etc/authbind/byport/80
然後就成功了
flora@*******:~/shop_platform$ authbind --deep pipenv run gunicorn --bind 0.0.0.0:80 "app:create_app()"
Loading .env environment variables...
[2021-10-28 14:08:57 +0000] [23160] [INFO] Starting gunicorn 20.1.0
[2021-10-28 14:08:57 +0000] [23160] [INFO] Listening at: http://0.0.0.0:80 (23160)
[2021-10-28 14:08:57 +0000] [23160] [INFO] Using worker: sync
[2021-10-28 14:08:57 +0000] [23170] [INFO] Booting worker with pid: 23170
使用 nginx
參考 Deploy a Flask Application to Ubuntu 18.04 Server,發現使用 nginx 的話,app 就不一定要監聽 80 port 了,nginx 會幫忙把 request 轉過去。
ModernWeb 2021 年會,10 月 22 日的議程,Vic Huang 講者的講題就是 NGINX misconfiguration in Real World。今天也讓我摸到一點 nginx 的邊邊了。
GCP 上 VM 的 External IP 是 34.80.108.187。設定好 nginx 後,連線到 34.80.108.187 會看到:
接下來,只要在 nginx 的設定中指定的 proxy_pass http://127.0.0.1:8000;
這個地方,啟動 app 去監聽就大功告成了。不過要先建立種子資料,不然網站會空空的。
建立資料表
pipenv run flask db upgrade
檢查是否建立成功
flora@*******:~/shop_platform$ mysql -u root -p
mysql> SHOW DATABASES;
mysql> USE shop_platform;
mysql> SHOW TABLES;
+-------------------------+
| Tables_in_shop_platform |
+-------------------------+
| alembic_version |
| cart |
| cart_item |
| category |
| order |
| order_item |
| order_status |
| payment |
| payment_status |
| product |
| question |
| rating |
| reply |
| shipping_status |
| user |
+-------------------------+
15 rows in set (0.00 sec)
看樣子沒問題
建立種子資料
pipenv run flask seed run
sqlalchemy.exc.DataError: (pymysql.err.DataError) (1366, "Incorrect string value: '\\xE5\\x88\\x86\\xE9\\xA1\\x9E...' for column 'name' at row 1")
[SQL: INSERT INTO category (id, name, insert_time, update_time) VALUES (%(id)s, %(name)s, %(insert_time)s, %(update_time)s)]
[parameters: ({'id': 1, 'name': '分類 1', 'insert_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530780), 'update_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530798)}, {'id': 2, 'name': '分類 2', 'insert_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530800), 'update_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530802)}, {'id': 3, 'name': '分類 3', 'insert_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530804), 'update_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530805)}, {'id': 4, 'name': '分類 4', 'insert_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530807), 'update_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530808)}, {'id': 5, 'name': '分類 5', 'insert_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530810), 'update_time': datetime.datetime(2021, 10, 28, 18, 1, 42, 530811)})]
(Background on this error at: https://sqlalche.me/e/14/9h9h)
失敗了。我本地的電腦建立種子資料都沒出問題,我試著檢查,是否是編碼問題。首先,查看我本地 MySQL (版本 8.0.23)的編碼設定:
再對照 VM 上 MySQL (版本 5.7.36)的編碼設定:
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
參考資料:[MySQL] 為什麼 MySQL 要設定用 UTF8MB4 編碼 UTF8MB4_UNICODE_CI
試著把編碼改成 utb8mb4,查過一些文章後,底下這些指令,mysql 都跟我說 ERROR:
mysql> ALTER DATABASE shop_platform CHARACTER SET utf8 COLLATE utf8mb4;
mysql> ALTER DATABASE shop_platform CHARACTER SET utf8 COLLATE 'utf8mb4';
mysql> ALTER DATABASE shop_platform CHARACTER SET utf8 COLLATE utf8mb4_unicode_ci;
mysql> ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
mysql> ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8mb4;
後來根據 How to set utf8mb4 on MySQL 5.7 (windows),使用 mysql> SET NAMES utf8mb4;
,有效果了,再次查詢編碼的結果是:
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
character_set_database 和 character_set_server 的編碼設定還是和我本地的 MySQL 不一樣。再次嘗試產生種子資料,依然是 Incorrect string value。
上述操作,我猜應該是在未用 use database-name 指令指定資料庫時做的。下述操作,則是有下 use shop_platform 這個指令
再根據關於MySQL如何修改編碼問題(utf8轉utf8mb4)--解決表情存庫,繼續設定:
mysql> SET character_set_server = utf8mb4;
mysql> SET character_set_database = utf8mb4;
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
看起來是有用,可是後來我發現,我一離開 mysql 操作介面,再重新登入,上次改好的設定都不見了⋯⋯
看著 character_sets_dir 那一行,我決定到 /usr/share/mysql/charsets/ 資料夾看看是怎麼回事。根據 README,可以設定的編碼都列在 Index.xml 檔案裡。而 Index.xml 裡面沒有 utf8mb4 也沒有 utf8mb4_unicode_ci,只有 utf8、utf8_general_ci、utf8_bin。難怪 mysql> ALTER DATABASE shop_platform CHARACTER SET utf8 COLLATE utf8mb4;
會跟我說是 invalid 的設定。
但是根據 PHP PDOException: SQLSTATE[HY000] [2019] Can't initialize character set utf8mb4 執行了 mysql> show character set like 'utf%';
+---------+------------------+--------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+------------------+--------------------+--------+
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
+---------+------------------+--------------------+--------+
裡面倒是出現了 utf8mb4。
嘗試 mysql> ALTER DATABASE shop_platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
就沒有報錯了。看來是我對語法不熟悉惹得禍。接著再嘗試新增種子資料,依然是 Incorrect string value
話說,我在找資料的過程中才知道,就算修改了預設編碼的設定,也不會自動套用到之前已經建立的資料庫上,所以還需要再對已經建立的資料庫設定一次。改預設編碼的話,可以到 /etc/my.cnf 或 /etc/mysql/my.cnf 去改
我在 /etc/mysql/my.cnf 檔案最下方新增了
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
collation-server = utf8mb4_unicode_ci
init-connect='SET NAMES utf8mb4'
character-set-server = utf8mb4
重新啟動 mysql 後,再次登入 mysql(這次是用 sudo -u root -p 登入,之前登入時,開頭都沒有加上 sudo)
mysql> SHOW variables LIKE 'character_set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
看來預設值 OK 了。然後再設定一次已經建立的資料庫的編碼設定:mysql> ALTER DATABASE shop_platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
。不過種子資料還是建立失敗了。所以失敗的原因,大概跟是不是用 sudo 登入無關。
參考這篇文章 Mysql 插入中文错误:Incorrect string value: '\xE7\xA8\x8B\xE5\xBA\x8F...' for column 'course' at row 1,用另一個語法查看資料表的編碼
mysql> show create table category;
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| category | CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`insert_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
原來編碼還是 latin1。難道說,即使我改了 shop_platform 這個 database 的編碼設定,但 shop_platform 中已經建立的資料表,並不會自動套用新的編碼設定?因為有滿多張資料表的,我決定 drop shop_platform,再重新建立一次。這樣新建的 database 和 table 都能套用新的 utf8mb4 預設值。然後我終於成功了!
執行 flask
flora@*******:~/shop_platform$ pipenv run gunicorn --bind 127.0.0.0:8000 "app:create_app()"
Loading .env environment variables...
[2021-10-29 07:51:02 +0000] [3552] [INFO] Starting gunicorn 20.1.0
[2021-10-29 07:51:02 +0000] [3552] [INFO] Listening at: http://127.0.0.0:8000 (3552)
[2021-10-29 07:51:02 +0000] [3552] [INFO] Using worker: sync
[2021-10-29 07:51:02 +0000] [3561] [INFO] Booting worker with pid: 3561
就能連上網站了
我本來是想把伺服器開在 127.0.0.1:8000 的,因為 nginx 的設定是 proxy_pass http://127.0.0.1:8000;
,我以為一定要開在那個位置,app 才收得到 request。但是開失敗了,可能是有什麼程式已經在那個位置執行了。結果改成在 127.0.0.0:8000 開,居然也能連得上。看來我對 IP、PORT 或是 nginx 的運作方式還不夠瞭解。
目前是我自己手動開啟伺服器,應該有什麼辦法可以讓電腦自己開伺服器。
update: ssh 連線斷掉以後,http://34.80.108.187/products/ 這個網址依然沒有壞掉。看樣子,有沒有保持 ssh 連線,和遠端 VM 上的 app 服務有沒有在運作,是兩回事。所以,為什麼沒辦法把伺服器開在 127.0.0.1:8000,是因為,在前一次的 ssh 連線時,我已經在那個位置開啟伺服器,ssh 連線斷掉後,伺服器還是在那個位置運作。
根據 How to kill a process on a port on ubuntu,刪除在某個 port 上運行的 prcoess,語法是:
flora@*******:~/shop_platform$ sudo netstat -lpn |grep :8000
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 3359/python
flora@*******:~/shop_platform$ sudo kill -9 3359
flora@*******:~/shop_platform$ sudo netstat -lpn |grep :8000
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 3563/python
flora@*******:~/shop_platform$ kill -9 3563
-bash: kill: (3563) - No such process
先查詢在某個 port 上運行的 prcoess 的 PIN,然後指定該 PIN 予以刪除。不過,我操做起來,刪完第一次後, process 還在,但是換了個 PIN,要再針對新的 PIN 重刪一次。
Comments
Post a Comment