hugoで生成した静的ページをCircleCIでさくらのレンタルサーバへ自動アップ

2019.2.23

はじめに

hugoを使って記事を書き、bitbucketのgitリポジトリへプッシュしたらCircleCIで静的ページを生成してレンタルサーバへアップするみたいなことを、やってみましたので紹介します。

ローカルで行うことは、下記の2つだけになるのでとても快適な執筆活動が行えるようになります。

使用しているレンタルサーバは「さくらのレンタルサーバ ライトプラン」です。

CircleCIの設定方法

CircleCIに追加したリポジトリの中に、下記のディレクトリ1つとファイル1つを作成する必要があります。 個々に記載した設定をCircleCIが自動的に読み取ってファイルをPushしたときにデプロイ処理を実行してくれます。

下記のようなイメージでは位置すればOKです。

hugo-site/
├── .circleci/
|       └── config.yml
├── archetypes
├── assets
├── config
├── content
├── data
├── layouts
├── static
└── themes

config.ymlの内容

config.ymlの中身は下記のようにしました。

  version: 2
  jobs:
    build:
      docker:
        - image: cibuilds/hugo:latest

      working_directory: ~/hugo

      steps:

        - checkout

        - run:
            name: Update enviroment
            command: apk update && apk add python3 lftp

        - run:
            name: Building blog pages
            command: hugo -d note.mokuzine.net --cleanDestinationDir

        - run:
            name: create tar
            command: tar -zcvf note.mokuzine.net.tar.gz note.mokuzine.net

        - run:
            name: deploy
            command: python3 deploy.py

記述の内容を簡単に説明していこうと思います。

docker:
    - image: cibuilds/hugo:latest

cibuilds/hugo:latestというdockerイメージが既にあったので、これを利用してデプロイまで行うようにしました。

- checkout

bitbucketの設定したリポジトリからソースコード(hugo)のデータを取得します。

    - run:
        name: Update enviroment
        command: apk update && apk add python3 lftp

データを取得したら、コンテナ内のパッケージをアップデートして、python3とlftpをインストールします。

    - run:
        name: Building blog pages
        command: hugo -d note.mokuzine.net --cleanDestinationDir

hugo -dコマンドを使ってサーバに上げるためのコンテンツデータを生成します。

    - run:
        name: create tar
        command: tar -zcvf note.mokuzine.net.tar.gz note.mokuzine.net

ここからは私の独自方法になりますが、生成したコンテンツデータをtarで固めます。

    - run:
        name: deploy
        command: python3 deploy.py

自作のデプロイ用スクリプトdeploy.pyを実行して、レンタルサーバへ先程作成したtarファイルをアップロード、データ入れ替えを行います。

deploy.pyの内容

CircleCIからレンタルサーバへのアップロードはdeploy.pyが行っています。 さらに、deploy.pyreplace.phpというPHPスクリプトを実行して、古いコンテンツデータとアップロードしたコンテンツの入れ替えを行っています。 さくらインターネットのライトプランではphpが標準で使用できますので、このようにしています。

import subprocess
import tarfile
from ftplib import FTP
import shutil
import os
import urllib.request

ftp = FTP(
    "アップロード先のレンタルサーバ",
    "FTPユーザ",
    passwd="FTPユーザのパスワード"
)

cont = 'note.mokuzine.net.tar.gz'
with open(cont, "rb") as f:
    ftp.storbinary("STOR ./www/"+cont, f)

repsh = 'replace.php'
with open(repsh, "rb") as f:
    ftp.storbinary("STOR ./www/"+repsh, f)

url = 'http://アップロード先のレンタルサーバ/replace.php'

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
    body = res.read()

ftp.delete("./www/" + repsh)

コンテンツの入れ替えは、replace.phpが行い、入れ替えが終わったらreplace.phpをサーバ上から削除して、サーバに不要なファイルを残さないようにしています。

replace.phpの内容

新しく生成したコンテンツデータのアップロードが完了したあとは、replace.phpを使って古いコンテンツを削除して新しいコンテンツを解凍しています。 解凍が終わったら、tarファイルを削除してゴミを残さないようにしています。

<?php
    echo "repace";
    $sitename = "note.mokuzine.net";
    $zipfile = $sitename . ".tar.gz";
    if (file_exists($zipfile )) {
        echo shell_exec("rm -rf {$sitename}");
        echo shell_exec("tar -zxf {$zipfile}");
        echo shell_exec("rm -rf {$zipfile}");
    } else {
        echo "error";
    }
    return;

echo "repace";など一部エコーしている部分は、手動でコンテンツ入れ替えのテストしているとき名残なので、特に意味はないです。

Related.