話題の記事

microCMS + Gatsby + GitHub Actions + S3 でJamStackのチュートリアル

2020.11.06

What is Jamstack?

ここ数年でよく聞くようになったワード。
Jamstackとはウェブサイトを構築および運用するための、技術の組み合わせです。
JavaScript・API・事前にレンダリングされたMarkupの組み合わせでJamStackとのこと。
(以前はJAMStackといってたけど、最近はJamstackだったりする)

Jamstackは、
「ウェブをより速く・より安全に・より簡単に拡張できるように設計されたアーキテクチャ」であり、
生産性を最大化するツールやフレームワーク、ライブラリやワークフローなどを
組み合わせて構築されるもの、とのことです。
jamstack.orgより

従来のCMSではアクセスがあったとき動的にページを生成しますが、
Jamstackではデプロイ以前に必要なページを生成します。

具体的には、下記。

  • Webサイトのフロントエンド全体(HTMLファイルやjsファイルなど)は事前に生成する
  • アクセスがあったときは事前に生成したコンテンツをそのまま返す
  • 動的機能が必要ならJavaScriptで実現

Benefits of Jamstack

Jamstackアーキテクチャを使うことによるおもな利点です。
jamstack.orgより

  • セキュリティの向上
    サーバやデータベースなど、インフラから複数のシステムをなくすことができるため、
    そもそもの攻撃対象や脆弱性を減らすことが可能です。
    コンテンツは事前に生成し、読み取り専用で提供できる。

  • スケール
    サイト全体がCDNから提供されることも可能になるため、
    面倒なスケーリングプロセスやキャッシュ機構を管理する必要はありません。
    これにより、シンプルなデプロイと高い可用性を実現できます。

  • パフォーマンス
    CDNから提供されるコンテンツはuser experienceや
    コンバージョンに大きな影響を与えます。
    Jamstackのコンテンツは、ユーザーの近くにあるCDN利用できるので、
    高価で複雑なインフラを導入することなく、非常に高いパフォーマンスを実現可能です。

Jamstack Architecture

よくblogがJamstackの構築例として紹介されていますが、ここでもblogを例にします。
よくあるJamstackの構成とフローは↓のような感じです。

1.記事をpost

まず、記事投稿者がHeadless CMSを通して記事をpostする。
※ContentfulとかmicroCMSとか

2.通知

記事がpostされると、そのタイミングでCIへ通知をします。
通知機能を持っているHeadless CMSもありますし、そういった機能がない場合は
AWS Lmabdaなどを使って自前で用意することも可能。

3.build

コンテンツ更新を通知されたCIはbuild processを実行します。
ソースリポジトリ(Githubとかcode commit)に対して、Site generatorを使って
CMSからデータの取得とコンテンツの生成などを行う。
※gatsbyとかnextがsite generatorとして人気ですね

4.deploy

コンテンツを生成したらデプロイします。
S3やNetlifyにデプロイすればCMSにpostした記事を確認することが可能です。

environment

  • OS : MacOS 10.15.7
  • node : v14.10

※GithubとAWSのアカウントは作成済み

Create Jamstack Example

では実際にやってみましょう。
本稿では下記サービスを使用してJamstackアーキテクチャのblogサンプルを構築します。

setup microCMS

まずはHeadless CMSであるmicroCMSの準備をしましょう。
microCMSは日本産のHeadless CMSです。 会員登録すれば無料プランでもいろいろできます。

アカウント登録してログイン後、サービスの作成を行います。
その後、公式ドキュメントと同じく「news」APIを作成してみましょう。

  • API名 : news
  • エンドポイント : https://<サービス名>.microcms.io/api/v1/news
  • HTTPメソッド : GET / POST
  • Webhook : 後で設定
  • APIスキーマ : titleとbodyだけ追加

API作成後、APIプレビューを見るとcurlコマンドを確認できたり、動作確認が可能です。

また、
https://<サービス名>.microcms.io/settings/apikey
で見られるX-API-KEYとX-WRITE-API-KEYはあとで使用するので覚えておきましょう。  

このあたり、マニュアルを見れば詳細にわかるので、
参照しながらやってみてください。  

ここまでできていれば、↓のcurlコマンドを実行することで記事をpostすることができるようになります。

% curl -X POST "https://<サービス名>.microcms.io/api/v1/news" -H "Content-Type: application/json" -H "X-WRITE-API-KEY: <API KEY>" -d "{\"title\":\"タイトルその1\",\"body\":\"内容その1\"}"

microCMSの管理画面で登録したデータが表示されればOKです。

using Gatsby

次にstatic site generatorのインストールをします。
今回は手軽につかえて、microCMSなど各種サービスとも相性のいいGatsby.jsを使ってみましょう。

まずはnpmでcliをインストール。してgatsby newコマンドで新規アプリを作成します。
gatsby developコマンドで起動後、localhost:8000でデフォルトページが表示さればOKです。

% npm install -g gatsby-cli
% gatsby new my-example
% cd my-example
% gatsby develop

次に、microCMSと連携させるためにpluginをインストール。
API KEYなどの環境変数を簡単に扱うため、dotenvモジュールもインストールします。

% npm install --save gatsby-source-microcms
% npm install --save dotenv

そして、my-example/gatsby-configに下記設定を設定を行います。
後述するenvファイルの値をサービスIDとAPI KEYにセットするように記述してください。

//dotenvで環境変数セット
require("dotenv").config({
 path: `.env.${process.env.NODE_ENV}`,
});

module.exports = {
  siteMetadata: {
    title: `Gatsby Default Starter`,
    description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
    author: `@gatsbyjs`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
    //ここの設定を追加する
    {
      resolve: "gatsby-source-microcms",
      options: {
        apiKey: process.env.X_API_KEY,
        serviceId: process.env.SERVICE_ID,
        apis: [{
          endpoint: 'news',
        }],
      },
    },
  ],
}

my-example/.env.developmentファイルを作成してIDやKEYを記述しておきましょう。

SERVICE_ID=<microCMSで設定したサービスID>
X_API_KEY=<microCMSのX_API_KEY>

設定ファイルが記述できたら、news APIのデータ表示用ページを作成します。 下記のように、react&GraphQLでデータを表示するように記述すればOKです。
このあたり、詳しくはドキュメント を参照。

// pages/news.js
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"

const NewsPage = ({ data }) => (
 <Layout>
   <SEO title="ニュース" />

   {data.allMicrocmsNews.edges.map(edge => {
     const news = edge.node

       return (
        <React.Fragment key={news.id}>
         <div>
             <h2>{news.title}</h2>
         </div>
         <div>
            {news.body}
         </div>
        <hr />
       </React.Fragment>
       )
   })}
 </Layout>
)

export const query = graphql`
 {
    allMicrocmsNews(
     sort: { fields: [id], order: DESC }
   ) {
     edges {
       node {
         id
         title
         body
       }
     }
   }
 }
`

export default NewsPage

ページができたら再度developコマンドを実行してください。
localhost:8000/newsにブラウザでアクセスすると、
さきほどmicroCMSに登録したデータが表示されます。
これはアクセス時に取得しているわけではなく、public/page-data内に生成された静的なページです。

% export NODE_ENV=development
% gatsby develop

Create S3 bucket

生成したファイルのデプロイ先であるS3バケットを作成も必要です。
AWSコンソールにログインして、S3からbucketを作成してください。
アクセス権限やStatic website hosting設定をしたらOKです。
※ bucket設定はこのへん参考

using Github Actions & deploy to S3

次は、microCMSにデータがpostされたら、そのタイミングでビルドが実行されて
デプロイされるようにしてみましょう。
そのためにはまず、my-appをGithubにホストします。
※ .envファイルはpushしないように注意!
このへんを参照

Githubへmy-appをpushできたら、Github Actionsの設定を行います。
※Github Actionsについてはこのへん参照

リポジトリのActionsタブをクリックして、「 set up a workflow yourself」リンクをクリックすると、
そのままエディタが起動してワークフローをブラウザで記述できます。

# This is a basic workflow to help you get started with Actions

name: publish

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the main branch
on:
  repository_dispatch:
    types: [dispatch_cms]    

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      - name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: '14.x'
      - name: install modules
        run: npm install
      - name: build gatsby
        run: npm run build
        env:
          X_API_KEY: ${{ secrets.X_API_KEY }}
          SERVICE_ID: ${{ secrets.SERVICE_ID }}
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      - name: Upload file to S3
        env: 
          S3_CONTENTS_BUCKET: ${{ secrets.S3_CONTENTS_BUCKET }}
        run: |
          aws s3 sync ./public s3://$S3_CONTENTS_BUCKET/ --quiet

ここでは、microCMSから通知を受け取ると、nodeのセットアップを行い、
npm run buildコマンドで静的ファイルの生成を実行します。
ビルドが完了したら、publicディレクトリ以下をS3へアップロードを行います。
* 参考 : GitHub ActionsワークフローでAmazon S3のオブジェクトにアクセスする

このGithub Actionsを動かす前に、各種機密情報をsecretsに登録しておく必要があるので、
Githubでsettings -> Secretsを選択し、下記変数を登録しておきましょう。

X_API_KEY
SERVICE_ID
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
S3_CONTENTS_BUCKET

最後に、microCMSのWebhook機能を使い、POST /news のタイミングで
Github Actionsを実行するように設定します。
Githubでアクセストークンを発行し、下記URLで設定をしましょう。
https://<サービスID>.microcms.io/apis/news/settings/webhook

これで準備が整いました。
ローカルからcurlコマンドでnews API(POST)を実行すると、
Github Actionsが動いてgatsbyのbuildを行い、生成したファイルをS3にアップロードします。
公開したS3のURLにアクセスすると、登録したnewsデータが表示されます。

Summary

今回はJamstackの簡単なサンプルを作成してみました。
site generator ・ hosting ・ CI/CD ・ CDNと、
Jamstackではさまざまなサービス/ライブラリの組み合わせが可能です。
今後もこれらのツールやライブラリ、サービスがさらに拡充していくと思われますので、
さらにこのアーキテクチャは採用されていくのではないでしょうか。

参考

  • https://www.infoq.com/jp/news/2020/10/introducing-jamstack/?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global
  • https://qiita.com/ozaki25/items/4075d03278d1fb51cc37
  • https://www.mitsue.co.jp/knowledge/blog/frontend/201912/10_0000.html
  • https://microcms.io/blog/what-is-jamstack/
  • https://qiita.com/utautattaro/items/6a8ad2408656329abd2d
  • https://www.to-r.net/media/jamstack-demo/
  • microcms + githubactions
  • https://tech-blog.s-yoshiki.com/entry/197