在Daocloud上部署Typecho

  • 2019 年 11 月 25 日
  • 筆記

大概是幾個月前我在 v2ex 上看到了Daocloud的宣傳,開始接觸到了 Docker 這個神奇的容器引擎和 Daocloud 這個基於 Docker 技術的雲平台

類似於將貨物打包在集裝箱上供遠洋貨輪運輸的方式,我們可以將自己想要的程式及其運行環境打包成 Docker 鏡像,然後把鏡像上傳到伺服器上運行。採用 Docker 部署應用的一個優勢是你可以根據自己的需要靈活地配置你想要的環境,最後只需要把一個 Docker 鏡像交給伺服器就能運行了。至於為什麼要這麼做呢,這裡說的挺清楚的 >>>>>>什麼是 Docker?

<s>Daocloud每個賬戶都有2x的免費配額(每個x分別代表著128M記憶體的伺服器資源或者10G的存儲空間),沒有流量、運行時間之類的限制</s>,而且速度挺不錯,十分良心。於是我開始琢磨著看看能不能把這個blog遷移到 Daocloud 上,遷移遇到了一些坑,把坑都填了之後用起來感覺還是挺不錯的。在這裡分享一下我折騰的過程。

首先是資料庫的遷移,Daocloud 可以免費創建一個 50M 的資料庫,對於一個部落格來說是綽綽有餘(目前我這個2014年開的blog的資料庫導出的sql文件也就200多k),Daocloud 自帶一個 phpmyadmin ,所以導入過程和一般的主機沒什麼區別,這裡不再贅述。

其次是運行環境的配置,在 Daocloud 中所有的應用都是以 Docker 鏡像的方式發布的,所以我們需要解決的問題的就是如何構建一個我們想要的鏡像和如何部署這個鏡像。

Daocloud 還有另一個特點,那就是在鏡像重新部署之後,應用之前在運行時對自身容器的所有改動都將會丟失,直接變回鏡像構建出來的狀態,也就是說,如果我製作了一個 Typecho 的 Docker 鏡像,網站運行時創建的配置文件,上傳的圖片等等在重新部署之後都會丟失,這顯然不符合要求。

為此,Daocloud 同時也提供了 Volume 服務,這裡的Volume是「數據卷」的意思,顧名思義,它相當於一個外接的磁碟,它可以掛載到 Docker 容器中的某一個目錄上,應用運行時對這個目錄的更改直接對應於對這個磁碟的操作,彌補了容器重新部署時改動不能保存的弊端。

所以我最終選擇的方案是,將 Typecho 所需要的 PHP 環境做成 Docker 鏡像,Typecho 的所有文件都放在一個 Volume 裡面,應用運行的時候再把這個 Volume 掛載到 Docker 容器的 /var/www/html 目錄上(虛擬主機的既視感),創建一個 128M 記憶體的應用和一個 10G 的 Volume,正好消耗完了兩個x的免費配額。

遷移網站之前得手動修改一下網站的 config.php ,把 MySQL 資料庫的連接資訊改成由 Daocloud 的環境變數獲取。原本我用的是 MySQL 擴展,看到PHP新版本已經被拋棄 MySQL 擴展了,乾脆換成 Pdo_Mysql 吧,修改後的程式碼如下

/** 定義資料庫參數 */  $db = new Typecho_Db('Pdo_Mysql', 'typecho_');  $db->addServer(array (    'host' => getenv('MYSQL_PORT_3306_TCP_ADDR'),    'user' => getenv('MYSQL_USERNAME'),    'password' => getenv('MYSQL_PASSWORD'),    'charset' => 'utf8',    'port' => '3306',    'database' => getenv('MYSQL_INSTANCE_NAME'),  ), Typecho_Db::READ | Typecho_Db::WRITE);  Typecho_Db::set($db);

然後把整個網站的程式和數據都傳到Volume上,這個過程還是很順利的。

接下來開始配置能運行 Typecho 的 PHP 環境的 Docker 鏡像,這裡需要用到 Dockerfile 來構建鏡像。(關於Dockerfile的介紹

這裡我選擇了官方的 PHP Apache鏡像為基礎鏡像

FROM daocloud.io/php:5.6-apache

默認的 PHP 鏡像很多擴展都沒有,所以我們得把要用到的擴展裝上去

# docker-php-ext-install 為官方 PHP 鏡像內置命令,用於安裝 PHP 擴展依賴  RUN apt-get update && apt-get install -y php5-curl php5-gd  # pdo_mysql 為 PHP 連接 MySQL 擴展  RUN docker-php-ext-install pdo_mysql

為了支援 rewrite(主要用來支援 .htaccess 隱藏 index.php ),加上這一行

RUN a2enmod rewrite

到目前為止構建的鏡像已經可以運行了,看起來也沒什麼異常,但很快我便發現,網站中的主題的文件無法在 Typecho 後台在線修改、附件無法上傳,根據我的推斷應該是容器中運行的 PHP 進程沒有操作 Volume 裡面的文件的許可權。

用 Daocloud 送的代金券開了個專業版之後,我開了個終端進入正在運行的應用,定位到 /var/www/html 再 ls -all 發現,裡面的文件所有者和組全都是 root ,難怪為什麼 PHP 進程會無權操作。我試著執行 chown -R www-data:www-data /var/www/html/ ,將裡面的文件所有者和組變回了 www-data ,文件寫入恢復正常。

經過一番測試我發現了一個規律,每次往 Volume 添加的文件的所有者默認都是 root,而 LAMP 的架構的網站運行的時候為了保證文件寫入,所有者應該是 www-data。針對這個問題,我現在要做的是讓它自己一開始就把 /var/www/html/ 裡面所有的文件的所有者都改成 www-data。

開始我在 Dockerfile 加入一行 RUN chown -R www-data:www-data /var/www/html/ ,再試,發現並沒有什麼變化。仔細想想,Volume 是在鏡像構建好之後部署的時候才綁定的,所以我在構建的時候更改目錄的所有者並沒有什麼用。

於是我換了個思路,把這個 chown -R www-data:www-data /var/www/html/ 放到了鏡像的啟動命令裡面。結果是網頁都打不開了。但我進入控制台定位到 /var/www/html 的時候發現文件所有者的確是變化了,說明這個命令還是起作用了,但這個命令執行的時候應該還是丟失了什麼。

我開始查找關於 Dockerfile 的 CMD 指令的資料,發現這麼一句:

Dockerfile 只允許使用一次 CMD 指令。 使用多個 CMD 會抵消之前所有的指令,只有最後一個指令生效。

但我這個 Dockerfile 之前並沒有用過 CMD 指令,莫非是這個指令把基礎鏡像的 CMD 指令給抵消了?!帶著這個問題,我找到了基礎鏡像的 Dockerfile >>>基礎鏡像的Dockerfile的程式碼

發現它的啟動命令

CMD ["apache2-foreground"]

根據我的猜測應該是後來的 CMD 指令覆蓋了這個。於是我試著把 apache2-foreground 也寫了進去,由於 CMD 只能運行一條命令,所以我把這兩個指令寫到了一個 sh 文件裡面,這裡命名為 start.sh ,具體內容如下:

#!/bin/bash  set -e  chown -R www-data:www-data /var/www/html/  apache2-foreground

然後在 Dockerfile 添加的內容(這裡我直接把 start.sh 放到了 /var/www 目錄下運行):

COPY . /var/www  WORKDIR /var/www  RUN chmod 755 ./start.sh  # 避免PHP無法寫入掛載到Volume的文件  CMD ["./start.sh"]

測試之後發現我的猜測是正確的√,應用是先掛載了 Volume 之後才開始啟動的。

後來我搜索了下發現網上也有一些關於類似的情況的介紹 http://blog.csdn.net/wsscy2004/article/details/25980675 https://yq.aliyun.com/articles/53990

至此這個應用基本上已經能用了。應用部署了這個鏡像之後每一次啟動都會自動把 /var/www/html 裡面所有文件的所有者和組都改成 www-data ,所以如果在 Volume 中新上傳文件不能被 PHP 進程操作的話,重啟一下應用就好了。

附上最終的 Dockerfile

# 使用官方 PHP-Apache 鏡像  FROM daocloud.io/php:5.6-apache  # docker-php-ext-install 為官方 PHP 鏡像內置命令,用於安裝 PHP 擴展依賴  RUN apt-get update && apt-get install -y php5-curl php5-gd  # pdo_mysql 為 PHP 連接 MySQL 擴展  RUN docker-php-ext-install pdo_mysql  RUN a2enmod rewrite  COPY . /var/www  WORKDIR /var/www  RUN chmod 755 ./start.sh  # 避免php無法寫入掛載volume的文件  CMD ["./start.sh"]

使用這個 Dockerfile 時記得把 start.sh 和 Dockerfile 放在同一目錄,再用 git 提交到你的倉庫中

至此搬遷完成,順便綁定了域名,由於我的域名沒有備案,流量是經過境外伺服器反代回中國的伺服器的,速度稍慢了些,而且這個反代伺服器對 POST 請求的數據大小限制在了10kb以內,使用未備案的自定義域名的話,過長的文章,評論,附件提交將會出現500錯誤,用分配的二級域名則沒有這個限制,有點坑爹。不過網站速度相比我原來的vps還是快了許多,等我有機會再給這個域名備案吧~(ps:現在綁定域名需要備案號了)

———11月7日更新——— Daocloud 計費策略調整,原來的 Daocloud 雲平台更新為「雲端測試環境」,每個應用啟動24小時後會自動停止,並且會定期清理閑置的應用。對於我這種個人用戶來說,網站已經不適合部署在它自有的雲平台裡面了,不過利用它構建 Docker 鏡像把網站部署到自己的vps上還是非常不錯的,所以我又把網站搬回vps了