オンプレミスMySQLをAuroraへ移行する際に、困ったこととその対応

こんにちは、インフラエンジニア の 加藤(@kuromitsu_ka)です。

この記事は Enigmo Advent Calendar 2021 の 24 日目の記事です。

今回は、オンプレミスのMySQLを、Auroraへ移行する際、困ったことと対応したことを記載します。

移行方式をざっくりいうと、オンプレミスのMySQLより取得した、論理バックアップ(mysqldump)とバイナリログを使用してAuroraへ移行しました。移行のため、リストア環境と、リストア後のデータのチェック環境を構築したので先にその説明を記載して、困ったところと対応を記載していきます。

リストア環境

オンプレミスMySQLサーバから取得した、バックアップファイルをAuroraへ適用する環境を作りました。EC2のMySQLと、Auroraとでレプリケーションを貼り、EC2のMySQLにデータを投入してリストアしました。バックアップファイルのダウンロードや、リストアジョブのスクリプト実行は、リストアジョブサーバから実行します。 f:id:enigmo7:20211220161725p:plain

リストア後のデータのチェック環境

Auroraへのデータのリストア後に、データの差分確認をする環境としてMemcachedも用意しました。それぞれのテーブルのデータの合計チェックサム値をMemcachedに入れて比較しました。こちらも、チェックのジョブスクリプト実行は、リストアジョブサーバから実行します。 f:id:enigmo7:20211222002116p:plain

困ったこといくつか。

本題のAuroraへの移行で困ったことは、5個あり、順を追って記載します。

  1. やんごとなき理由で、Auroraへのリストアに物理バックアップが使えず困った。
  2. Auroraの仕様上、バイナリログを直接適用できずに困った。
  3. Auroraへのリストアで、バイナリログの適用に2日間もかかって困った。
  4. リストア環境を作ったものの、バイナリのログ適用がコケて困った。
  5. リストア後、バイナリログ適用したデータの時間がなぜか9時間ずれて困った。

困ったこと その1

やんごとなき理由で、Auroraへのリストアに物理バックアップが使えず困った。

Auroraへのリストアには、物理バックアップが、サポートされていました。こちらが使えると安心だったのですが、問題があり使用できませんでした。結果的に論理バックアップから、リストアすることとなりました。

物理リストアできなかった原因

オンプレミスのMySQLには、パラメータ(innodb_undo_tablespace)が設定されていました。Auroraでは、こちらが変更不能になっているため、物理バックアップでは、Auroraへのリストアでコケていました。パラメータ変更には、MySQLサービスの再起動が必要なため、論理バックアップを使用することとなりました。

  • エラーログ
    Auroraのerror/mysql-error-running.log、error/mysql-error.logより確認したエラーログ
[ERROR] InnoDB: Unable to open undo tablespace './/undo001'.
[ERROR] InnoDB: Plugin initialization aborted with error Generic error
[ERROR] Plugin 'InnoDB' init function returned error.
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[ERROR] Failed to initialize builtin plugins.
[ERROR] Aborting
  • 問題のパラメータ
    undo ログが分割するテーブルスペース数を設定するパラメータ(innodb_undo_tablespace
物理リストアできなかった値
- innodb_undo_tablespace = 2
物理リストアできる値
+ innodb_undo_tablespace = 0
パラメータ名 変更可能
innodb_undo_tablespace いいえ

困ったこと その2

Auroraの仕様上、バイナリログを直接適用できずに困った。

Auroraへは、直接バイナリログ適用できない仕様で、リストア環境を用意することになりました。BINLOGコマンドは、スーパーユーザーの権限での実行が必要なのですが、Aurora では、スーパーユーザー権限を利用することはできないそうで、コケてしまいました。そのため、リストア環境としては、EC2にMySQLを作成して、レプリケーションを貼りました。
※他社事例では、バイナリログをデコードして生のクエリを直接Auroraに適用する方法もありましたが、移行作業をしていた当時は見ていませんでした...。

  • 適用コマンド
# mysqlbinlog --no-defaults --database=${DB_NAME} --start-datetime=${START_TIME} --stop-datetime=${STOP_TIME} bin-log.00xxx 
  | mysql -h ${AURORA_ENDPOINT} -P 3306 -u admin -p
  • エラーログ
ERROR 1227 (42000) at line 7: Access denied; you need (at least one of) the SUPER privilege(s) for this operation

困ったこと その3

Auroraへのリストアで、バイナリログの適用に時間がかかって困った。

Auroraへのリストアでは、バイナリログ適用(1桁GB程度でも)に2日間ほどかかりました。こちらは、AuroraのDBインスタンスのマシンリソースの増強と、Auroraのパラメータを変更したところ高速化できました。結果、バイナリログ適用は、20分程度に納まるようにできました。

  • 対応したこと
    AuroraのCPU、メモリ使用率を見つつインスタンスタイプを変更
サーバ インスタンスタイプ CPU メモリ(GB)
オンプレミスMySQL 12 252
EC2のMySQL(リソース増強前) db.t3.small 2 2
EC2のMySQL(リソース増強後) db.r6g.4xlarge 16 128
  • Auroraのパラメータより、バイナリログ出力を一時的にOFFに変更
Binlog_format = OFF

困ったこと その4

リストア環境を作ったものの、バイナリのログ適用がコケて困った。

バイナリログ適用がタイムアウトしたり、2,3割適用できたところでコネクションエラーになったりもしました。デバッグの際も、タイムアウトとコネクションエラーしか出ず、原因がぱっと見ではわからずで困りました。結果として、リストア環境のMySQLパラメータを変更することで、解決しました。

  • エラーログ
ERROR -- : Lost connection to MySQL server during query (Mysql2::Error::ConnectionError)

MySQLパラメータ変更

リストア環境のEC2のMySQLで、パラメータチューニングを行いました。ひとまず、タイムアウト関係のパラメータを操作しましたが、一部バイナリログデータを適用できず止まってしまうものもありました。続いて、パケットサイズのパラメータも変更しましたが、エラーは続いていました。最終的に、プロセスが、十分なメモリを確保できていないのかなと考えて、メモリキャッシュ関係のパラメータを変更して解決しました。

connect_timeout = 172800
net_write_timeout = 172800
net_read_timeout = 172800
wait_timeout = 172800
interactive_timeout = 172800
  • パケットの最大サイズのMySQLパラメータ(最大値に設定)
max_allowed_packet = 1073741824
  • メモリキャッシュ関係のパラメータ(最大値に設定)
    ※変更したパラメータ「innodb_buffer_pool_size」は、読み込み、書き込みのパフォーマンス向上にも使われるパラメータです。
innodb_buffer_pool_size = 1G

困ったこと その5

リストア後、バイナリログ適用したデータのうち、タイムスタンプ関係のデータで、なぜか9時間ズレが発生して困った。

バイナリログで適用したデータのみ、何故か9時間ズレるという問題も経験しました。MySQLタイムゾーン関係の、パラメータを変更して対応しましたが、解消しませんでした。結果として、バックアップ取得元の、バイナリログフォーマットのパラメータを変更して解決しました。

タイムゾーンのパラメータ
オンプレミスのMySQLも、Auroraも、リストア環境のEC2のMySQLJSTに設定していました。

  • バイナリログ取得元のMySQLと、EC2に作成したMySQLのパラメータ
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
  • Auroraのパラメータ
    Auroraの場合、パラメータ「time_zone」が、データベースのデフォルト値になります。
+------------------+------------+
| Variable_name    | Value      |
+------------------+------------+
| system_time_zone | UTC        |
| time_zone        | Asia/Tokyo |
+------------------+------------+

バイナリログフォーマットのパラメータ

  • binlog_format」をMIXEDから、ROW変更
    レプリケーション元の binlog_format を ROW とすることで、バイナリログ適用の際、クエリでなく実行結果がレプリケーションされるようになるそうでした。バックアップ取得元の、オンプレミスのMySQLにてパラメータ変更した結果、無事、データが一致しました。
バイナリログを適用した、データのタイムスタンプのデータが9時間ズレたパラメータ
- binlog_format = 'MIXED'
バイナリログを適用した、データで時間のズレがなかったパラメータ
+ binlog_format = 'ROW'

感想

オンプレミスMySQLのAurora移行は、たいへんでしたが楽しかったです。

明日の記事の担当は 人事総務 の 廣島 さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

Apache Airflowを使ってみた感想

こんにちは。サーバーサイドを担当している橋本です。 この記事は Enigmo Advent Calendar 2021 の23日目の記事です。
普段は Ruby on Railsを書くことが多いですが、とあるプロジェクトでAirflowを使った既存バッチの性能改善を行いました。プロジェクトはAirflowについて全く知らない状態からスタートして学ぶことが多かったので、この記事でAirflowの紹介と開発の感想を書いていきたいと思います。

Airflowとは?

Airflowとはワークフローの管理ツールで、あるタスクを実行したら次のタスクを実行するといった形で一連のタスクを管理するものになります。Airflowではjobの実行順や依存関係をDAGで定義していて、DAG自体はPythonで作成されています。

簡単にDAGのコードのご紹介です。(環境構築は省略させていただきます。)
下記のプログラムは 文字列をprintするタスクを順番に実行するものです。DAG で実行時刻やDAGの名前の設定をします。PythonOperatorを使ってタスクを定義し、一番下の行の execute_task1 >> execute_task2 で実行するタスクの順番を定義します。

import airflow
from airflow.operators.python_operator import PythonOperator
from airflow.models import DAG
from datetime import datetime

args = {
    'owner': 'airflow'
}

dag = DAG(
    dag_id = 'advent_calendar_tasks',
    default_args = args,
    schedule_interval = '0 0 * * *'
)

def task1():
    print('task1')

def task2():
    print('task2')

execute_task1 = PythonOperator(
    task_id = 'execute_task1',
    retries = 2,
    python_callable = task1,
    dag = dag)

execute_task2 = PythonOperator(
    task_id = 'execute_task2',
    retries = 2,
    python_callable = task2,
    dag = dag)

execute_task1 >> execute_task2

管理画面にアクセスするとDAGの情報を見ることができ、実際に実行することもできます。

f:id:enigmo7:20211222093417p:plain

使ってみてよかったこと

モニタリングがGUIから管理できる

DAGのスケジュールや実行状況を同一画面で見ることができるので、モニタリングがしやすかったです。また、DAGの実行やスケジュールの on/offの設定も管理画面からできるので、コマンドを実行する手間を減らすことができたのが便利でした。

タスク単位で確認できる

管理画面のDAGの詳細画面ではタスクを個別で見ることができます。プログラム作成時にタスクを上手く分割すればDAGが実行するタスクを簡単に確認できます。

f:id:enigmo7:20211221144035p:plain

タスク実行に便利なライブラリが提供されている

実際のタスクではSQLを実行したりファイルをアップロードする必要があると思いますが、DAGで使用できるライブラリが提供されています。プロジェクトではFTPをアップロードするために FTPHookというライブラリを使いましたが、Pythonで標準で使える ftplibよりも簡単にFTPを扱うことができました。

使ってみて難しかったこと

Pythonに不慣れだったこと

プロジェクトではRuby on Rails => Pythonへ刷新したのですが、普段はRubyを書いているのでPythonに慣れるのが大変でした。

セキュアな情報の設定が初見だとわかりにくかったこと

Airflowではセキュアな情報をConnectionsで管理していますが、最初はDAGに接続情報を書いてしまいました。あらかじめドキュメントを読んでAirflowのコンセプトを理解する必要があると感じました。

まとめ

ここまでAirflowの紹介と感想を書きましたが、開発中は学ぶことが多く新鮮な気持ちで開発ができました。 明日の記事の担当は インフラエンジニアの加藤さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

macOSでdocker環境をどう早くしたか

こんにちは、サーバーサイドエンジニアの Steven です。

この記事は Enigmo Advent Calendar 2021 の22日目の記事です。

今回は Vagrant 環境をリプレースすることとなった Docker 環境をどう早くしたかについて説明します。

スタート地点は Vagrant 環境

エニグモでは以前から VirtualBoxVagrant によるローカル環境を使って、開発してました。 使い勝手は完璧ではなかったのですが、開発する分には問題がとくになく長年活用されました。 ただし、それは構築ができたらの話で、構築時間が長いのと、時間が立てば立つほど自ずと新しい構築エラーが発生して、随時対応しないといけない状態でした。 エンジニアの場合、超えられない問題ではなかったのですが、デザイナーなどテクニカルな知識がそれほどない方だと、サポートしてもハードルがかなり高かったです。 VM 内で使っていた OS も古いバージョンの CentOS で、いずれ更新しないといけなかったです。

Docker 環境ができました

Docker で新しいローカル環境を作ることで以上の問題を解消できないかと動いてくださったエンジニアがいました。 そうすれば、構築時間の短縮と、安定性の改善、使い勝手の向上を実現できるからです。

構築して想定通り改善はできましたが、代わりに新しい問題が現れました。 それもよくあるパターンのようで、Vagrant 環境よりパフォーマンスが悪く、使い物にならない環境になってしまいました。 ローカル環境とはいえデータセンターにあるサーバーとつなげたりするので、もともとの Vagrant 環境でもはじめからそれほど早くはなかったです。 なので、それ以上パフォーマンスが落ちると、対策が必須となってしまいます。

当時はチューニングを試みましたが、根本的な改善が見られず、Docker 環境の導入は一旦保留となりました。

レスポンスタイム比較

ページ Docker環境 Vagrant環境
トップ 9.95s 1.07s
検索結果 9.22s 1.89s
マイページ 9.30s 1.79s

Docker Desktop for Mac について

この場合 Docker 環境のパフォーマンスが悪かったのはコンテナーと macOS 間のファイル IO のパフォーマンスが悪かったからです。 アプリケーションコードをすべてメモリーに保持するなど、ファイル IO がそれほど発生しないアプリケーションの場合は問題にならないこともあると思いますが、私達の場合はファイル IO がどうしても多く発生する環境なので、必然的にパフォーマンスが悪かったです。

Docker Desktop for Mac では、Linux 環境と違って、コンテナーはそのまま macOSカーネルに実行されておらず、macOS 上で動く VM の中にある Linux カーネルによって実行されています。 なぜそうなっているかというと、macOSカーネルではコンテナー化のサポートがなくて docker のようなコンテナーを実装することができないからです。 なので、bind ボリュームを通してコンテナー内から macOS 側にあるファイルにアクセスする時は、VM の中から osxfs(レガシー)か gRPC FUSE というファイルシステムレイヤーを通して、macOS 側のファイルが読み込まれます。 ただし、抽象化が多いところから、ケースによってそのレイヤーがかなり遅くて、ネイティブのアプリケーションと比べ物にならないことが珍しくないです(当然といえば当然ですが)。

Docker Desktop for Mac でキャッシュのオプションもありますが、試した結果それほど影響が大きくなくて、違いに気づけるかどうかというレベルでした。

Docker チームでパフォーマンスの問題を認識していて、改善を以前から試していますが、ファイルシステムの実装はかなり難しいもので、トレードオフが多いです。 パフォーマンスを高くするために工夫すると、整合性などの面で新しい問題が現れたりします。 パフォーマンスは改善傾向にありますが、満足の行かないケースがまだ多いと思います。

Mutagen とは

Docker Desktop が提供するオプションだけでは解決できない問題なので、サードパーティーによる解決策を探しました。 最初は docker-sync を試しましたが、最終的に Mutagen に落ち着きました。

Mutagen はファイル同期とネットワークのフォワーディングのためのツールで、本来はクラウドにあるリソースをローカル環境で使うためのものかと思いますが、最近は docker compose のサポートが追加されて、docker 環境と合わせて使うことが可能になりました。 ファイル同期は rsync によるものなので、パフォーマンスがよくて、かなり堅牢なものです。

docker compose と合わせて使う場合は macOS とコンテナーの間に、VM 内に同期されているファイルのコピーが用意されます。 コンテナ内から本来 bind であったボリュームへのファイルアクセスが発生した場合は macOS 側のファイルを読みに行かず、VM のファイルにのみアクセスするようになります。 アプリケーションのファイル処理が VM 内で完結するため、macOSVM 間のファイルのやり取りが激減して、パフォーマンスのボトルネックがなくなります。

Docker チームでも Docker Desktop に Mutagen を正式的に導入する動きが以前ありましたが、導入で追加の複雑さが生じることから、やめることとなったようです。その代わりに gRPC FUSE を優先するようになりました。

導入例

Mutagen の導入はかなり簡単です。

まずはbrewで Mutagen をインストールします。

$ brew install mutagen-io/mutagen/mutagen-beta # 現在はβバージョンが必要です

続いて、docker-compose.ymlmacOS 側のファイルにアクセスするためのボリュームを用意します。

services:
  bm_on_rails:
    # ...
    volumes:
      - rails-source-sync:/bm_on_rails

  bm_php:
    # ...
    volumes:
      - php-source-sync:/home/web/bm_php

volumes:
  rails-source-sync:
  php-source-sync:

最後に、同じファイルで、x-mutagenの項目の配下に Mutagen の設定を指定します。

x-mutagen:
  sync:
    rails-source-sync:
      mode: 'two-way-resolved'
      alpha: './volumes/bm_on_rails'
      beta: 'volume://rails-source-sync'
    php-source-sync:
      mode: 'two-way-resolved'
      alpha: './volumes/bm_php'
      beta: 'volume://php-source-sync'

alphabetaは同期のエンドポイントとなります。 意味合いはmodeによりますが、以上ではalphamacOS 側のパス、betaは Docker のボリュームを指しています。 modeにはいくつかの選択肢がありますが、コンフリクトを自動解消するとして、alphaの変更をどんな時も優先したい場合はtwo-way-resolvedが適切です。 詳しくはこちらをご確認ください。

セットアップができたら、次は Docker 環境をmutagen compose upで立ち上げます(Mutagen の新しいバージョンではmutagen-compose up)。 docker composeコマンドを使うと、Mutagen の処理がスキップされるので、間違えないよう注意してください。 ただのラッパーなので、docker composeでできることはmutagen composeでもできるはずです。 ちょっと不便かもしれませんが、Mutagen の開発者側でdocker composeをそのまま使えるように検討されているようです。

環境の初回起動に macOS 側のファイルが VM 内にコピーされるので、ファイルの量によって時間がかなりかかってしまう可能性があります(私達の場合は 10分ぐらい)が、二回目以降は Mutagen を使ってないのとあまり変わらなくなります。

導入後、アプリケーションのパフォーマンスは Vagrant 環境よりやや早くなりました。 データセンターへのアクセスがどうしても発生するので、そのパフォーマンスで目標を達成としました。

注意

Mutagen は Docker Desktop のバージョンに依存していますので、Mutagen のバージョンと Docker Desktop のバージョンに気をつけてください。 Docker Desktop のアップデートが来る度にすぐアップデートすると、Mutagen が動かなくなってしまう恐れがあります。

Mutagen の docker compose サポートはまだβですが、バグがほぼなくとても安定しています。

調整

デフォルトで macOS 側のファイルすべてが VM 内に同期されるので、.gitディレクトリなど VCS 用のファイルを同期したくない場合は追加の設定が必要となります。 任意のファイルの同期をスキップすることも可能です。詳しくはこちらをご参照ください。

x-mutagen:
  sync:
    defaults:
      ignore:
        vcs: true
    # ...

特に設定がない状態では Mutagen に同期されているファイルのオーナーとグループ、パーミッションはコンテナー内でデフォルトなものとなってしまいます(オーナーとグループはおそらく root となります)。実行権限のみ同期されます。 なので、コンテナー内のファイルのオーナーとグループ、パーミッションを調整したい場合は追加の設定が必要となります。 詳しくはこちらをご確認ください。

x-mutagen:
  sync:
    # ...
    php-source-sync:
      # ...
      configurationBeta:
        permissions:
          # php コンテナー内ではファイルのオーナーとグループを apache にする
          defaultOwner: 'id:2000'
          defaultGroup: 'id:2000'

同期オプションは他にもいろいろありますので、必要に応じてご確認ください。

同期セッション重複問題

Mutagen を導入してから、社内で特にファイル同期に関する問題が報告されなかったのですが、少しずつ、MacBook の CPU 使用率が高い、見覚えのない差分がgit statusに出てる、などと相談が来るようになりました。

差分の問題はファイル同期と関係がありそうだと思ったので、その方向で調査を進めたら、相談者の MacBookmutagen sync listが本来2つしかないはずのセッションを大量出力しました。

問題出力

--------------------------------------------------------------------------------
Name: rails-source-sync
Identifier: sync_93JIPMqNq5WkYV20nV9Wq4XdvyBr3CXz3oonMfIkyYQ
Labels:
    io.mutagen.compose.daemon.identifier: JH67_K5QB_5FG6_F4UH_OG45_7EKG_LBBY_7IPY_Z4ME_IKQY_HVSG_PPTU
    io.mutagen.compose.project.name: docker_buyma
...
--------------------------------------------------------------------------------
Name: php-source-sync
Identifier: sync_bzryoXJaLbxevdit2ODkZuGz2RChyN2C2W5wS8CdbdU
Labels:
    io.mutagen.compose.daemon.identifier: JH67_K5QB_5FG6_F4UH_OG45_7EKG_LBBY_7IPY_Z4ME_IKQY_HVSG_PPTU
    io.mutagen.compose.project.name: docker_buyma
...
--------------------------------------------------------------------------------
Name: php-source-sync
Identifier: sync_FaC9uwjuhGziEeggNVbPI2EFgGUE1sxtKArzva4rSck
Labels:
    io.mutagen.compose.daemon.identifier: T3PW_AONQ_MWDI_T5BO_Z6EH_6PQB_6CJZ_336T_M2KO_AXQH_ZSAQ_DQ7E
    io.mutagen.compose.project.name: docker_buyma
...
--------------------------------------------------------------------------------
Name: rails-source-sync
Identifier: sync_tPPnFvmEjlwKhLtkrudgukM3Qc7AHdTOc0QANYjwAmN
Labels:
    io.mutagen.compose.daemon.identifier: T3PW_AONQ_MWDI_T5BO_Z6EH_6PQB_6CJZ_336T_M2KO_AXQH_ZSAQ_DQ7E
    io.mutagen.compose.project.name: docker_buyma
...
--------------------------------------------------------------------------------
...

出力を見てわかりますが、同期セッションが重複しています。 設定は一緒ですが、daemon.identifierというものだけがそれぞれ違います。

daemon.identifierは Docker デーモンの id です。 デーモンはもちろん一つしかなくて、再起動しない限り id も変わらないはずです。

問題は Docker 開発環境を終了せず、MacBook を再起動すると、発生していました。 原因としては再起動前に Mutagen のセッションを終了しなければ、再起動後に Docker 環境を立ち上げた時、古い同期セッションが残っていながらも、Docker デーモンの id が変わった影響で、同期セッションがまだ作成されてないと Mutagen が判断して、新しい同期セッションを作ってしまうということでした。

該当するイッシューはあります(問題を解消できないか検討中のようです)。 https://github.com/mutagen-io/mutagen/issues/243

対策としては Docker 環境起動後にmutagen sync listの出力を確認して、重複したセッション(現在の Docker デーモン id を使ってないセッション)があった場合、mutagen sync terminateでそのセッションを終了するようにスクリプトを作成しました。

MacBook 停止の際に Mutagen の同期セッションを必ず終了するようにするのも考えられる対策です。

M1 対応

新しい MacBookARM アーキテクチャーの M1 チップを使うことで macOS の業界で動かなくなってしまったものが多くあります。 なので、M1 対応をした時はもしかすると Mutagen が動かなくなってしまうと懸念しましたが、問題なく動きました。 インストールで調整は必要なく、同期も支障なく行われていますので、M1 で使う分には問題ないと思います。

docker-sync について

Mutagen を使うようになる前に 0.5.1 の docker-sync をまず試しました。

docker-sync は ruby の gem と unison を生かした、Docker Desktop 専用のファイル同期ツールです。 仕組みも設定方法も Mutagen に似ていますが、Mutagen と違って macOS 側で動くプログラムが多く、rbenv/ruby などのインストールが必要です。 Vagrant での環境構築ではそれらのインストール時に様々な問題が発生していたため、今回は rbenv/ruby などのインストールは避けたかったです。

docker-sync で初回同期は問題なくて、パフォーマンスも Mutagen と同じぐらい改善されましたが、ファイル同期が不安定で、macOS 側でファイルが変わっても、コンテナー内に反映されないことが多々ありました。 ファイル同期を強制するにも docker-sync のデーモンを再起動するしかなく、そうする度に CPU 使用率が跳ね上がって、MacBook がドライヤーなみにうるさくなったりしていました。 docker-sync のイッシューを確認したら、開発者が問題を認識していても解決策が思いつかない状態のようでした。

なので、以上のことから docker-sync はあまりおすすめできません。

終わりに

Docker Desktop for Mac のファイル同期のパフォーマンスの悪さで悩まされた期間が割と長かったのですが、Mutagen を導入することで完全に解消して、デメリットもほぼないので、同じ悩みを抱えられているなら、ぜひ導入をご検討ください。

Docker チームによる Docker Desktop のパフォーマンス改善に期待したいところですが、Mutagen レベルのパフォーマンスが実現されるまでどれくらい時間がかかるのかがわからない状態なので、そうなるまでサードパーティーに頼るしかないかと思います。

明日の記事の担当はエンジニアの橋本さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

New Normalなオフィス作り

f:id:enigmo7:20211115184555p:plain こんにちは、Corporate IT/Business ITを担当している足立です。

この記事は Enigmo Advent Calendar 2021 の 21日目の記事です。 代打として2回目の登場です。

2021年の前期はオフィスリニューアルPJの業務に追われていました。
コロナ禍に突入し出社とリモートワーク両方に最適化された環境を構築する事をミッションとして動きましたので、 今回はコーポレートIT目線で実施した事を書きたいと思います。

旧オフィスの課題 電源問題

リニューアルするなら旧オフィスで課題だった部分を改善したいと思いました。
総務的な話になりますが、特に電源については下記問題がありました。

  • 電源
    • 旧オフィス時にはOAタップが少なくタコ足配線かつ数珠繋ぎ状態で、あちらこちらにあり危険な状態
    • 電子レンジを2台同時に利用した際にブレーカーが落ちiMacが強制シャットダウン状態になった事がありアンペア増強・単独系統への見直しが必要

→ リニューアル後
座席毎に6個口OAタップが設置されました。

f:id:enigmo7:20211111175745p:plain
6個口のOAタップ
全てではありませんが、座席にモニターを常設しUSB-Cによる電源供給も可能にしました。 最大65 Wの電力を供給出来るので、PCの電源供給と映像信号が1つのケーブルで対応可能になりました。
f:id:enigmo7:20211111180216p:plain
DELL P2419HC

オフィス レイアウト作成時に社内に設置する電子レンジは執務エリアと電源系統と別にして頂きました。 絶対にサーバールームの電源系統は他に影響しないように手配しました。

電話周り

電話システムはオンプレ型のPBX(レガシーPBX)で構成されていたため、頭を悩ませていました。 これも総務的な話ですが、気づいたら電話周りも担当していたので、どうにかしようと思いました。

課題

  • オフィスに設置する物理的な機器であるため、移設時には工事などが必要(PBX・配線)
  • 運用保守は専門の業者に依頼をしている
  • 今後、移転の場合は通信キャリア、専門業者との調整が必要になり時間がかかる
  • 当然、電話は社内でしか使用出来ない
  • PBXがサーバールームに設置してあり場所を取る(兎に角、邪魔でしょうがない)
    f:id:enigmo7:20211111181622p:plain
    旧 電話構成

→ リニューアル後
クラウドPBXであるDialpadを導入しました。

f:id:enigmo7:20211111182341p:plain
Dialpad
導入した事によりPCやスマホで会社の電話を利用出来るようになりました。
着信については会社が保有している電話番号(03番)にて着信するように、キャリア自動転送を利用してDialpadで発行された050の番号へ転送するようにしました。 ただし、発信はDialpadで発行した050の番号で発信する事になります。
f:id:enigmo7:20211111183643p:plain
シン・電話構成

最近、Dialpadでも0ABJ番号(03番)を別途、機器を設置せずにライセンス購入のみで利用出来るようになりましたので03番で発着信したい場合は、そちらを利用すると良いと思います。
導入後はWEB上で電話関連の設定が出来るようになりました。

  • 転送機能
  • 留守番電話
  • IVR設定(音声ガイダンス)
    他にも色々と機能がありますが、特にIVRが利用出来るようになったので内容に応じてBUYMAカスタマーサポートやfondeskへ誘導出来るようになりました。

キャリア自動転送をする際にエニグモの固定電話回線はISDNだった為、キャリアに依頼してオペレーターの方に対応してもらうか電話機の操作で転送設定をする必要がありました。 ただ、従来の電話機は処分する必要もあり電話機の操作による設定は利用出来なくなり、かと言ってオペレーターの方に依頼する場合、変更まで日数がかかるので思い切って電話回線を光収容化しキャリアのWEBページ上で転送設定が出来るようにしました。

f:id:enigmo7:20211111191750p:plain
IVR構成一部
(この構成はモダンな情シス Kajinariさんの事例を参考とさせて頂きました。)

IP固定電話
電話機は完全に無くすつもりで考えていましたが、バックオフィス部門から電話機が必要と言われたので 5台 POLYCOM VVX 350を設置しました。

f:id:enigmo7:20211111192945p:plain
VVX350
こいつが厄介だったのは、日本国内では購入は可能だが、サポートが受けられないのが難点でした。 お取引があるベンダーさん何社かに問い合わせしましたが、どこも販売までしか対応出来ないと言われ 覚悟を決めた上での購入でした。 不明な部分については基本、英語のマニュアルを翻訳して調べたり勘に頼ったりして設定しました。 それでも分からない部分についてはDialpadサポートの方が教えてくれました。

FAX
コロナ禍直後は複合機から受信したFAXをメール送信→Zapier→Slackで通知、Googleドライブに格納と言う構成でしたが、課題もありました。

  • 複合機の仕様上、用紙が切れるとFAXのメール送信が出来ない
  • 送信が社内のみでしか利用出来ない
  • PBXを撤去したいから電話線引きたくない

課題を無くす為、KDDIのペーパーレスFAXを導入しクラウド化を行いました。 当初は「FAX.PLUS」の導入も検討していましたが、FAXを利用する業務の大半が経理チームで主に銀行とのやり取りだったので、何かトラブルがあった際に日本企業の方が意思疎通が早いのかなと思いKDDIにしました。 WEB上でFAXの送受信が出来れば支障は無いので、特にこだわりはありませんでした。

f:id:enigmo7:20211115101934p:plain
シン・FAX システム構成
導入後、FAX受信はメール添付機能を利用し、旧構成と同じくZapierを利用してSlack上に受信通知、Googleドライブへ保存するようにし FAX送信時はペーパーレスFAXのサイトにログインして使用するので自宅からでもFAX送信出来るようになりました。

受付システム・座席予約(ホテリング)

電話の話にも通ずるのですが、受付をどうするかも課題でした。 従来の受付ではエントランスに電話機を設置し総務担当が取次するスタイルで お客様がお見えになる際は「ご来社カード」と呼ばれる入退室管理の用紙に必要事項を記入して頂くフローでした。

ただ、このままだと下記課題が残ります。

  • 受付の内線電話を撤去しなければオンプレPBXを撤去出来ない
  • 外来者の入退室管理が紙による記入かつ集計作業が業務負担になっている

f:id:enigmo7:20211115120848p:plain
旧エントランス

そこで「ACALL RECEPTION」を導入しました。
導入後、来客通知はSlackに変わり、お客様がお見えになった際は別途、設置したラベルプリンターから入館証が発行されるようになり 内線電話による受電対応が無くなり、入館履歴がシステム化され集計作業も不要になりました。

f:id:enigmo7:20211115120156p:plain
シン・エントランス

ただ、一部部署にて宅配業者がお見えになった際にSlackの通知だと作業中に気づかないと言う相談があった為 宅配業者専用ボタンを作成しACALLとDialpadを連携、そこだけはIP固定電話にて着信する運用となりました。

座席予約システム(ホテリング)
新しいオフィスは面積が今までの半分になる為、フリーアドレスを採用する事になりました。 リモートワークが主流になり、座席数がそこまで必要無くなりますが、その際に上司から座席予約システム導入を検討するよう指示がありました。

f:id:enigmo7:20211115144007p:plain
フリーアドレス
f:id:enigmo7:20211115144049p:plain
フリーアドレス2

個人的には必要なのか?と思いましたが、席のダブルブッキングや出社している人をひと目で可視化する為にも必要でした。 また、WEB MTG用に個室ブースを8箇所設置する為、座席予約システム導入がマストになりました。

f:id:enigmo7:20211115144139p:plain
WEB MTG用個室ブース

導入検討をしていた当時、ベストなソリューション選定に大変悩みました。 現在はコロナ禍を想定した座席予約システムが増えて来ましたが、当時としては・・・

  • 社内のコミュニケーション 円滑化を目的としたシステム(抽選式で座席を決めるシステム)
  • IoTに特化した座席予約システム(各座席にセンサーを設置する為、費用も高額、電池交換も必要)

弊社としてはWEB上かスマホで予約してはい、終わり!ぐらいなシンプルな機能を求めました。 ただ、上記の様に希望する要件と違ったシステムばかりでした。

悩んでいる矢先に受付システムで導入しようとしていたACALLに座席予約(ホテリング)機能がローンチされるとの情報が耳に入りました。 内容を見てみると希望する要件を満たすのではと感じ、受付システムと一緒に導入してみました。

f:id:enigmo7:20211115145935p:plain
座席マップ 一部
導入当初は予約した席にチェックインする作業に慣れない人も居ましたが、現在ではすっかり慣れました。 チェックインとは事前に予約した席に来たらACALLのスマホアプリで座席に貼ってあるQRコードを読み込む作業です。 予約した時刻から15分以内にチェックインしないと予約がキャンセルされます。 この機能が無いと予約したにも関わらず席を利用しない人が現れた際に他の人が利用する事が出来ないので重要な機能です。

特にWEB MTG用の個室ブースは1時間単位で利用する事が多く、システムの利用頻度は高めです。通常予約システムを導入した会社によっては利用しなくなるケースがあると聞いたことがありますが、弊社は業務に欠かせないシステムとなりました。

入退出システム

同時進行でシステム導入や移設手配をしている矢先に今度は入退出システム導入の話が出てきました。 オフィスの一部分だけは入居しているビルが管轄している入退出システムを利用しているのですが、C工事に該当するエリアについては自社で入退出システムを入れる必要がありました。従来ではセキュリティ会社が販売しているオンプレのシステムを利用していましたが、このタイミングでリプレイスする事となりました。 (管理コンソールがIEでしかログイン出来ない・・・)

代表からは「顔認証」で入退出出来るようにして欲しいとオーダーがありました。 当初はクラウドタイプの入退出システムをベースに顔認証を付ける構成を考えていましたが、お見積を取ると費用がかなり高額になる事が分かりました。 顔認証を諦めてもらい、スマホアプリやFeliCaを利用したシステムを役員へ提案しました。

プレゼン時に代表からは「顔認証」を捨てきれない印象があり、再検討するよう指示があり 「色々、見た上で提案しているんだから、他にあるんだろうか・・・」と思っていたので思わず「じゃあ、おすすめのシステムあれば見てみます」と 逆質問に近いように返答したところ、代表の口から「Safieとか」と言われ早速、見てみると「Safie Entrance」なるものが。

クラウド録画カメラのシステムとしては知っていたのですが、顔認証での入退出システムがあるのは知りませんでした。 早速、連絡を取り仕様や費用面を確認すると従来の顔認証システムに比べて圧倒的に安価に導入でき月々の費用もかなり安くなる事が分かり導入が決定。 若干、「こんなに良いものあるなら早く言ってよ」と思いましたが、代表のひと言が無ければ導入出来なかったと思います。

f:id:enigmo7:20211115155257p:plain
SafieEntrance
エニグモでは5箇所に設置しました。事前にSafieEntranceで使用するiPadを準備しケーブルを最小限にする為に電源はPoEにて供給する事にしました。 通信についてはテストした結果、Wi-Fiでも動作は問題ありませんでしたが有線LANで行っています。以前は鍵を使って物理的に入退出していた場所は全て顔認証になりエリア毎に入退出出来る従業員を制限しています。導入してみると顔さえあれば入出出来るのでが大変便利です。以前だと鍵にかけ忘れなどあり、それが無くなったので物理的なセキュリティレベル向上にも繋がりました。

個室ブース

以前に比べWEB MTGの需要が増えました。エニグモでも基本、MTGはZoomで行う事が増え、その度に会議室が不足する事になりました。 その為、上司の案で個室ブースを設置しました。

f:id:enigmo7:20211115161344p:plain
個室ブース
設計当初、防音になると聞いていたので各ブースにはLANケーブルを敷設しました。昔、ITサポートの仕事をしていた時にあるお客様のご家庭に防音部屋があり、その部屋だけWi-Fiが受信出来なかった経験がありました。使用する材質によっては著しくWi-Fiの強度が低下する恐れがあったのでお守り代わりに引くことをリクエストしました。 設置後に通信が不安定になるとWEB MTGに取っては致命傷になる事を危惧していました。実際に設置後にZoomを利用した際にインターネットの速度が不安定ですと表示された事があり、やっぱり引いといて正解だと心から感じました。 現在はオフィスに必要不可欠な場所となり、出社が多い日は予約出来なくなる事もあります。

もし個室ブースを設置を検討している場合はブース内の空調と照明にはこだわった方が良いと思います。 密封されている空間なので空調を重要ですし、窓が無い場合は照明を明るく出来るようする事をオススメします。

最後に

社内ネットワークについて書こうと思いましたが基本、現状維持のままでの移設だったので特段書く事も無く割愛しました。 ただ、Wi-Fi6に対応させようかと思ったのですが、サポート切れか今後会社が移転する機会があればその時で良いかと思ったので何もしませんでした。 あとは社内のAV機器周りについても担当したのですが、それはまた別の機会にでも書きたいと思います。 (これで1本書ける内容なので。)

新しいオフィスになり半年以上経過し、日々働いていると本当に良いオフィスになったと実感します。 このタイミングで様々なものを導入させて頂いて、短期間で担当した事は自分に取って財産になりました。 そして、導入に関してGoサインを出してくれた上司、役員の皆様に感謝の気持ちでいっぱいです。

明日の記事の担当は サーバーサイドエンジニアのstevenさんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

Next.js + Material UI v5 でフロントエンドアプリケーションを作成する

Next.js + Material UI v5 でフロントエンドアプリケーションを作成する

なぜこの記事を書いたのか

こんにちは。エニグモでサーバサイドエンジニアをしております、寺田(@mterada1228)です。

この記事は Enigmo Advent Calendar 2021 の 20 日目の記事です。

業務では主に Ruby on Rails を使っているのですが、最近新しいチャレンジとして、フロントエンドの勉強をしています。

そこで、Next.js + Material UI(以降 MUI)を使った Web アプリケーションの開発にチャレンジすることにしました。

ただ、この2つは全く異なる開発形態のフレームワークですので、一緒に使うためにはちょっとしたセットアップが必要になります。

参考にするため色々と検索してみましたが、なかなか求めている検索結果が得られなかったことと、なぜこのようなセットアップが必要になるかまで詳しくまとめられているものがなかったので、今回自分で調べて一つの記事を書いてみることにしました。

なお、本記事では Next.js で MUI を使うためのセットアップに焦点を絞っているので、Next.js のプロジェクトを立ち上げる部分は説明しません。

その部分を詳しく知りたい方は、公式チュートリアルを参考にしてもらえると良いかと思います。

Material UI を使うために必要なパッケージをインストールする

MUI v5 のパッケージをインストールしていきます。

ひとまず、コアな機能をインストールすれば十分かと思いますので、 @mui/material というパッケージをインストールしていきます。他のパッケージについては、必要に応じてインストールして下さい。

また、MUI ではスタイリングのために内部で CSS in JS のためのライブラリを使用しています。 こちらは、emotion もしくは styled-component のいずれかを入れる必要があります。

  • emotion を使う場合

    // with npm
    $ npm install @mui/material @emotion/react @emotion/styled
    
    // with yarn
    $ yarn add @mui/material @emotion/react @emotion/styled
    
  • styled-component を使う場合

    // with npm
    npm install @mui/material @mui/styled-engine-sc styled-components
    
    // with yarn
    yarn add @mui/material @mui/styled-engine-sc styled-components
    

next/link, @mui/material/Link の統合

Next.js からは、 next/link、MUI からは @mui/material/Link というコンポーネントが提供されており、名前からお察しの通りどちらもカスタマイズされたリンク(a タグ)を生成します。

この2つには競合する部分もありますが、ある場面では next/link を、また他の場面では @mui/material/Link を用いた方が便利というケースがあります。(どういった場面でどちらを使うべきか、という理由はサンプルコードの後で説明します。)

なので、状況に応じてどちらかのコンポーネントを返してくれるように、独自の Link コンポーネントを作成します。

src/Link.js

ここで重要になってくるのは65行目から86行目の部分で、href に設定された URL が、internalexternal のどちらであるかを判定して、 return するコンポーネントを分けている、ということです。

URL が internal な場合は、Next.js が提供する、next/link を返します。

これは Link がアプリケーション内のページ遷移であるときは、以下のような、Next.js が提供する各種機能を使用することができるからです。

  • Client-Side Navigation
  • Code Splitting and Prefetching

これらの説明は本記事の趣旨から逸れますので省きますが、詳しくはこちらをみて頂くと理解することができると思います。

URL が external な場合は、next/link である理由はあまりないので、豊富なスタイリング用の Props が使用できる @mui/material/Link を使うようにします。

実際にリンクを作成する時は、ここで作成した、src/Link をインポートする形になります。

pages/Index.js

独自 Theme を作成する

こちらは作成せずとも、MUI の default Theme を利用できますが、多くの場合アプリケーション独自の Theme を設定していくことになると思いますので、本記事でも取り上げていきたいと思います。

今回は src 配下に Theme ファイルを配置していきます。例は簡単のために、Typographyfont-size だけを設定したものになります。

src/Theme.js

独自で定義した Theme は、ThemeProvider を使って、アプリケーションに適用させることが可能です。

具体的な実装方法としては、 _app.js にて、Component より外側のコンポーネントThemeProvider を設定してあげれば OK です。

pages/_app.js

app.js, document.js の修正

最後に、Next.js で MUI を使用するために、_app.js_document.js の設定方法についてお話ししていきます。

はじめに、これから行う設定が何のためのものかというのを説明します。

MUI は元々、サーバサイドレンダリングされるものという制約のもと開発されています。 なので Next.js をはじめとした、クライアントサイドでレンダリングする可能性があるフレームワークを使用した場合に不具合が発生してしまいます。

具体的にどのようなことが起きるかというと、いわゆる FOUC(Flash Of Unstyled Content)というもので、画面上に CSS の当たっていないページが一瞬表示されてしまいます。

これはクライアントサイドレンダリング時に、HTML だけ表示されて、後から CSS が注入されるような流れになるため発生します。

なので、大まかに以下のような手順を踏むことでこの問題を回避していきます。

  1. サーバサイドレンダリング時に一度、コンポーネントツリーのレンダリングを行う
  2. そこから CSS を抜き出す(<style> を抜き出す)
  3. 抜き出した CSS をクライアントに渡してあげる

この手順では以下のパッケージが必要となりますので、事前にインストールしていきます。

// with npm
$ npm install @emotion/server @emotion/cache

// with yarn
$ yarn add @emotion/server @emotion/cache

まず、_document.js から説明していきます。_document.js は Next.js においてあらゆるコンポーネントの初期化時に実行されるコンポーネントですが、その特徴として、サーバサードレンダリング時に、サーバサイドで実行されるという特徴があります。

要するに前述した、1, 2 の手順をここで実行していくわけです。

サンプルコードは以下になります。

pages/_document.js

30行目からの処理に注目していきます。

getInitalProps はサーバサイドレンダリング時に、ページにあらかじめサーバから取得した情報を埋め混むことができるメソッドです。

getInitialProps 内の60行目から66行目までの部分で、一度ページコンポーネントレンダリングを行なっていきます(前述した 1. の手順に相当)

以降の処理で、レンダリングされたコンポーネントから CSS<style>)を抜き出し、emotion/cache を使ってキャッシュに保存します。(前述した 2. の手順に相当)

次にクライアントサイドの処理について見ていきます。

_app.js_document.js 同様に、あらゆるコンポーネントの初期化時に実行されるコンポーネントですが、クライアントサイドレンダリング時には、 _document.js は実行されず、_app.js しか実行されないという特徴があります。

ここでは、_app.js でサーバサイドレンダリング時にキャッシュに保存した CSS を受け取るといった方法で、クライアントサイドレンダリング時に発生する FOUC を回避します。以下がサンプルコードです。

11行目でサーバサイドレンダリング時に保存した CSS を取得します。

このキャッシュに保存された CSS は17行目のように、<Component> コンポーネントの外側を <CacheProvider> で囲ってあげることで、各ページコンポーネントに渡されます。

ここでお話しした内容は、MUI の公式ドキュメントでも詳しく説明されていますので、お時間ある方は合わせて見て頂けると理解が深まるかと思います。

おわりに

今回紹介したサンプルコードですが、https://github.com/mui-org/material-ui/tree/master/examples/nextjs で MUI が公式に提供しているものです。今後変更がある可能性もありますので、サクッとコピペして使いたい方は、紹介したリンクから取得いていただくのが確実と思います。

明日の記事の担当は データテクノロジーグループの堀部さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

GASとスプレッドシートを使ったOkta管理の一例

こんにちは。Corporate IT 所属の田中です。この記事は、Enigmo Advent Calendar 2021 の19日目の記事です。本記事では、Google Apps Script(以下、「GAS」といいます。)を使用して統合認証基盤サービスであるOktaの管理業務を効率化したことについて紹介したいと思います。 Oktaのグループにユーザーを追加する際、ユーザー数が多いと管理コンソール上で行うのに手間がかかり大変かと思います。
また、作業自体は簡単なものであるため業務アシスタントの方にお願いしたいと思いつつ、ロールの仕様上グループへのメンバー追加のみ権限を付与することも難しく、必要以上の権限付与を防ぐため結局自分で作業してしまうということもあるのではないでしょうか。
上記を改善するため、GASを用いてGoogle スプレッドシート上で簡単にメンバーのグループ追加を行えるようにしました。
更に、DB化されたスプレッドシートを利用して、Okta ユーザーのステータス情報を毎月コラボレーションツールのSlackに通知することで、月次のアカウント棚卸を効率化しました。

構成

仕組みはざっくり下図のとおりです。f:id:enigmo7:20211214002140p:plain *1*2

ユーザー及びグループ一覧の取得

OktaのAPIを使用してグループへユーザーを追加するためには、グループとユーザーそれぞれ一意に付与されているIDが必要です。 そのため、プロセスの前段としてGASでOkta APIからユーザー情報一覧とグループ情報一覧をスプレッドシートに同期しています。同期は、GASのトリガーを定期的に実行することで実現しています。
下図が、スプレッドシートへ反映されたユーザー一覧及びグループ一覧です。 「users-list」シートでは、ステータス、氏名、ローマ表記、email、ユーザーID、最後にログインした日時を取得しています。

f:id:enigmo7:20211214003056p:plain

また、group-listでは、グループ名、グループID、グループの説明を取得しています。 f:id:enigmo7:20211214003127p:plain

グループ追加

プロセスの後段として、上記取得した情報を基に、スプレッドシート上でOktaユーザーのグループ追加を行います。 下図左表「users-list」に追加する人の氏名を、右表「group-list」に追加先グループ名をそれぞれ入力すると、スプレッドシートのvlookup関数を利用してid等が自動入力されますので、後は下図右側の画像をクリックすると、GASでOkta APIを使用してグループへのユーザー追加プログラムが実行されます。 f:id:enigmo7:20211214003159p:plain

実行後、下図のように正常に追加されたことを確認しました。今後は、Slackの関連ページから本スプレッドシートを開いて簡単にグループへ多数ユーザーの追加ができそうです。 f:id:enigmo7:20211214003220p:plain

Oktaユーザーのステータスを月次棚卸

Oktaユーザーに関するステータスやログイン状況を利用して、スプレッドシート上で集計し月末にSlackに通知することにより、棚卸作業がやりやすくなりました。 f:id:enigmo7:20211214003254p:plain

最後に

いかがでしたでしょうか。私自身は非エンジニアで公開できる程綺麗なコードは書けませんためここでは非掲載とさせていただきますが、そんなレベルでも上記のような実装ができるぐらいGASは社内ITの連携に活用しやすく親和性のあるサービスかと思います。本記事の実装内容についてご興味ある方はご連絡くださいませ~。
また、enigmo Corporate ITでは各種クラウドサービス間の連携・自動化を実装できるようなコーポレートエンジニア及び部門を横断的にセキュリティ整備を行うセキュリティエンジニアを募集しております!ご興味ある方は下記求人からご応募お待ちしております!

明日の記事の担当は、サービスエンジニアリング本部の寺田さんです。お楽しみに。


株式会社エニグモ すべての求人一覧

hrmos.co

*1:Oktaのロゴは、次の利用規約に基づき使用しております。 https://www.okta.com/terms-of-use-for-okta-content/

*2:Google 製品のロゴは、次の利用規約に基づき使用しております。 https://about.google/brand-resource-center/brand-elements/#product-icons

あんしんしてお買い物してもらうためのカートUIリニューアルの裏側

f:id:enigmo7:20211210121849p:plain

こんにちは、BUYMAデザイナーの本田です。 BUYMAでは今年の2月〜7月にかけてカートの大幅なリニューアルを行いました。

PHPからRailsへの洗い替えや、パフォーマンスの改善がメインの施策だったのですが、UXの改善として、 上部に追従する購入ボタンよくある質問エリア を新しく追加しています。

ユーザーからよくある実際に届いている声の中から、

  1. 購入ボタンが遠くて見づらい
  2. キャンセルや返品がわかりにくくて不安
  3. 配送が遅い
  4. エラーがわかりにくい

上記4つの課題を解決するために、どのような想いのもとでデザインに落とし込んだのかについて紹介します。

比較

1. 購入ボタンが遠くて見づらい

BUYMAはカート画面でユーザーに確認していただきたいことが多く、1商品あたりの高さができてしまい、購入ボタンまでスクロール回数が多いことが課題となっていました。

複数商品をカートに入れていても、購入ボタンを見失わないでもらうために

  • 要素の見せ方整理をして、1商品あたりの高さを低くする
  • 購入ボタンを上部へ固定し、スクロール時も追従するようにする

の2つを行いました。

1商品あたりの高さを低く調節

2. キャンセルや返品がわかりにくくて不安

海外で購入した商品を日本へ送るCtoCショッピングサイトという特性上、

  • 偽物ブランドはないか
  • 返品はできるか
  • 送料や関税の負担はだれがするのか

などの質問をユーザーからいただくことが多く、専用の説明LPやガイドラインなどで説明しているのですが、それでも購入前になかなか気づけない・ユーザーの不安を拭えないことが、課題となっていました。

解決策として、LPへ遷移しなくてもカートページ内で補償サービスの内容を理解できるようにしたりユーザーからよくある質問エリアをまとめたエリア設置しました。

LPバナーをテキストへ変更、よくある質問を新設

3. 配送が遅い

海外配送となるため、送料の1番安いプランだと、繁忙シーズンには2週間以上かかってしまうこともあります。一方で、オプションメニューで、DHLやEMSなど海外の速達サービスを利用すると、+1,000円ほどで配送日数は大幅に短縮され、数日でお手元に届きます。

今までのUIですと、オプションメニューを選ぶことで、数日で到着することに気づかないまま、ご購入されるケースも多くありました。そのため、最短のプランがある時は、オプションメニューを選びやすくするUIパーツを追加しました。

最短プランがあるときはオプションメニューを選びやすくするUIパーツを追加

4. エラーがわかりにくい

今回のプロジェクトを機にすべてのエラー文言を洗い出し、どの状況下でエラーが発生してしまうのかを洗い出して整理し、提示するようにしました。

また、ユーザーは次に何をすればいいのか、ネクストアクションをきちんと提示することで、離脱率の低下を狙いました。

エラーパターン

検証

1. 購入ボタン

購入ボタンのクリックの割合は埋め込み:追従=8:2くらいで予想以上に利用されていました。 以前に他のプロジェクトで、商品詳細ページでも追従ボタンを設置してABテストをしていたので、あまり期待はしていなかったのですが、購入をある程度決めているカート画面には適切だったということがわかりました。

2. キャンセルや返品についてわからなくて不安

よくある質問エリアのクリックが全体の約2%で、割合としてはそこまで高くないですが、あんしんしてお買い物をするための後押しに少しでも貢献できたと思うと、デザイナーとして手応えがあったなと思います。

3. 配送が遅い

「最短の配送方法あり」のツールチップが表示されているユーザーの中で、さらに配送選択をしたユーザーの約45%が最短を選択していました。 サービスの特性などにもよるとは思いますが、追加料金を払っても早く商品が届いてほしいユーザーが多いことがわかりました。

まとめ

今回のカートリニューアルはユーザーの今の課題を解決する に加えて、あんしんしてBUYMAでお買い物を楽しんでもらうというビジョンを持ってサービス開発ができたと思ってます。

プロトタイプを定例で関係者全員に見せてフィードバックをいただけたり、プロジェクトチームの方全員と一丸になれたのもいい思い出です。来年も今年学んだことをベースにさらにいろんなことに挑戦していきたいです。

最後まで読んでいただきありがとうございました。 明日の記事の担当は 情シス の 田中さんです。お楽しみに。

株式会社エニグモ すべての求人一覧

hrmos.co