HTTPS の Wordpress を AWS LightSail に移行

経緯

弊社で運用している一部のサーバはクラウド事業者の VPSWordPress 環境を構築し、そこに証明書を入れて HTTPSWordPress を運用していました。 ただ、VPS の月額料金や証明書の更新に関わる購買や更新手続きといったコストといった点が問題視されていました。

無料の証明書である Let's Encrypt も考えましたが、できるだけ仕掛けを作らずに証明書の更新作業を自動化したいと考えました。 VPS の月額コスト見直しのタイミングもあったので、AWS LightSail に移行し証明書を自動更新する仕組みに切り替えました。

AWS LightSail とは

LightSail とは、AWS が提供する VPS サービスで、SSL アクセラレータ機能のあるロードバランサー(以下 LB )も使えます。 この LB には DNS 認証による無料の SSL/TLS 証明書を簡単に組み込むことができます。

SSL アクセラレータとは

SSL アクセラレータとは通信を TLS/SSL で暗号化する際に、暗号化や複合化の処理を専門に行う機能のことです。

  • 証明書管理の一元化
  • 負荷分散

といった効果があります。

今回の通信経路を図にすると以下のようになります。

f:id:kobayashi-ryotaro:20181127155450j:plain

LightSail ロードバランサー 作成

  1. AWS のコントロールパネルから LightSail のホーム画面に入ります。 f:id:kobayashi-ryotaro:20181127163621p:plain
  2. 「ネットワーク」→「ロードバランサーの作成」と進みます。 f:id:kobayashi-ryotaro:20181127164020p:plain
  3. 作成画面でリージョンや名前を設定して「ロードバランサーの作成」を押下します。HTTPS の設定は後で行います。 f:id:kobayashi-ryotaro:20181127164345p:plain
  4. ロードバランサー管理画面の「インバウンドトラフィック」で証明書の設定を行います。必要な項目を設定してください。 f:id:kobayashi-ryotaro:20181127165554p:plain
  5. ドメインの認証が終われば証明書の組み込みが完了します。 f:id:kobayashi-ryotaro:20181127165948p:plain

LightSail インスタンス作成

  1. ホーム画面から「インスタンス」→「インスタンスの作成」を押下します。 f:id:kobayashi-ryotaro:20181127170755p:plain
  2. 今回はWordPressの移行ということでバージョンの差異を懸念し、インスタンスイメージは「 OS のみ」「Amazon Linux」にしました。 f:id:kobayashi-ryotaro:20181127171149p:plain
  3. インスタンスプランを選んで名前を設定し、「インスタンスの作成を」押下してしばらくお待ちください。 f:id:kobayashi-ryotaro:20181127171316p:plain
  4. 作成が完了したら、先ほど作成したロードバランサーのターゲットインスタンスとして設定してください。 f:id:kobayashi-ryotaro:20181127172335p:plain
  5. 作成されたインスタンスにはパブリック IP で SSH 接続ができます。 f:id:kobayashi-ryotaro:20181127172544p:plain

WordPress の移行

WordPress はデフォルトだと ApachephpMySQL ですが、今回の環境は nginx+php-fpm + MySQL です。 各ミドルウェアのインストールや設定は割愛します。

移行に関しては基本的に

を移行すれば大丈夫です。

WordPressHTTPS

設定を間違えるとリダイレクトループしたりレイアウトが崩れるので注意してください。

リダイレクトループ対策

リダイレクトループとは、以下のようなループ現象です。

  1. LB が http で受ける
  2. LB が Web サーバに http で渡す
  3. Web サーバが301を返して https にリダイレクト
  4. LB が https で受ける
  5. LB が Web サーバに http で渡す
  6. Web サーバが301を返して https にリダイレクト
  7. 4に戻る

これを避けるために、nginx のコンフィグの server ディレクティブに以下の設定を追記します。 証明書に関する記述があれば削除してください。

   if ($http_x_forwarded_proto != https) {
      return 301 https://$host$request_uri;
    }

世の多くの LB や CDN は、自身を通過したときに http の拡張ヘッダである http_x_forwarded_proto に値を入れます。 これは配下のサーバが、もともとのアクセスが http なのか https なのかを判断可能にするためです。

この値を利用することで以下のような流れになり、ループを回避できます。

  1. LB が http でリクエストを受ける
  2. LB が http_x_forwarded_proto に http を入れて Web サーバに http で渡す
  3. Web サーバが http_x_forwarded_proto を評価し、http なので301を返して https にリダイレクト
  4. LB が https でリクエストを受ける
  5. LB が http_x_forwarded_proto に https という値を入れて、Web サーバに http で渡す
  6. Web サーバが http_x_forwarded_proto を評価し、 https なのでバックエンドにリクエストを渡す

WordPress の設定

こちらは設定を間違えるとレイアウトが崩れたりします。

wp-config.php に以下の設定を追記します。 php のアプリケーションは $_SERVER['HTTPS'] を評価してプロトコルを判定していることが多いためです。WordPress も例外ではありません。

  if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
      $_SERVER['HTTPS'] = 'on';

WordPressCSS の作成で自己参照することがあるのですが、こうすることでレイアウト崩れを防ぐことができます。

効果

証明書の自動更新機能で運用コストの削減ができました。 また DNS サービスである Route 53 を使えば AWS アカウントですべて管理でき、とても便利です。

まとめ

nginx や wordpress の移行作業が手間ではありますが、今回の移行により証明書の管理から解放されました。 手軽に HTTPSWordPress を作成したい場合は LightSail を検討してはいかがでしょうか。

AWS Elasticsearch Serviceの古いインデックスをcuratorを利用して削除してみました!

はじめに

こんにちは。インフラチームの高畑です。

今回、 curator を利用して AWS Elasticsearch Service に登録されているインデックスを削除するようにしてみたのでご紹介します!

curator とは

Elastic 社が提供する Elasticsearch の運用管理ツールで、インデックスのリスト表示や削除などが手軽に行えます。

curl を使用した場合のインデックスリスト表示

[user@hostname ~]# curl -XGET https://vpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxap-northeast-1.es.amazonaws.com/_cat/indices?v
health status index                       uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   api-nginx-access-2018.11.10 NtPFJq7gQ06fDZ8xtqarOA   5   1      35248            0      2.9mb          2.9mb
yellow open   api-nginx-access-2018.11.08 2zAfE-neQ0-2ghTfZQkxsA   5   1      40706            0      4.1mb          4.1mb
yellow open   api-nginx-access-2018.11.07 uxd-OGsbQq-k4qoteAPaGw   5   1      40406            0      4.1mb          4.1mb
yellow open   api-nginx-error-2018.11.03  9bAwxr8lSJSe1J3UE5AUfg   5   1        521            0    222.6kb        222.6kb
yellow open   ap-nginx-access-2018.11.05  VowpBW7SStmPm94xbG044A   5   1        168            0    223.3kb        223.3kb
yellow open   api-nginx-error-2018.11.04  rgKkhzhcR06eFnerLx54aw   5   1          1            0        8kb            8kb
yellow open   ap-nginx-access-2018.10.31  2LznB-GoTBm5fjb_T4bN9w   5   1        175            0    310.4kb        310.4kb
yellow open   api-nginx-access-2018.11.09 ysINQk6vRUO8FLGOiRcmnA   5   1      38718            0      3.8mb          3.8mb
yellow open   ap-nginx-access-2018.11.09  mU3ABP35Ste0VsJU64jpHQ   5   1        214            0    412.6kb        412.6kb
yellow open   ap-nginx-error-2018.11.08   wJIVXbnpSUGlpRr4KwcmwQ   5   1          8            0     61.2kb         61.2kb
yellow open   ap-nginx-access-2018.11.08  9aE7-pCTQtWbauq_7aI7xg   5   1        230            0    378.2kb        378.2kb
yellow open   api-nginx-error-2018.11.10  ZchNOQfCS4GKZ3FKWW1cfg   5   1          6            0     35.9kb         35.9kb
yellow open   api-nginx-access-2018.11.04 7D0J_NXVT6Wkmaf83B-kQw   5   1      35703            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.10.31  gnFgi1UGQbKHqCS1-m6eRg   5   1        883            0    320.6kb        320.6kb
yellow open   ap-nginx-access-2018.11.13  5VaWNCv9SNauh_1FCWSLrw   5   1          7            0     49.7kb         49.7kb
yellow open   api-nginx-access-2018.11.03 CBYDBAniRHiY-KzKiz8eiA   5   1      36741            0      3.2mb          3.2mb
yellow open   api-nginx-access-2018.11.02 RvdI42J0TrmC-lycFNWHjg   5   1      38100            0      3.6mb          3.6mb
yellow open   api-nginx-error-2018.11.09  qHjKeVtMTyOcbePYSVF5sA   5   1        538            0    220.2kb        220.2kb
yellow open   api-nginx-error-2018.11.05  _3PJCIgMT9mlbVh9jGzJNg   5   1          2            0     14.9kb         14.9kb
yellow open   ap-nginx-access-2018.11.01  IzjvuxKxRomqQdElicP10Q   5   1        157            0    260.2kb        260.2kb
yellow open   api-nginx-error-2018.11.01  oJnvclQkQtmr-btW9WkcIA   5   1          8            0     55.7kb         55.7kb
yellow open   ap-nginx-access-2018.11.03  kjFlEFifQEKXkVmfeomniw   5   1         96            0    227.8kb        227.8kb
yellow open   ap-nginx-access-2018.11.07  q4GQX8pORZS1slQSzJlsbQ   5   1        131            0    252.5kb        252.5kb
yellow open   ap-nginx-access-2018.10.30  Et4smDEyQuSLawlLOdnkHQ   5   1        144            0    294.3kb        294.3kb
yellow open   ap-nginx-access-2018.11.11  Owe3aa4gQ7aCs5mkkIA3kw   5   1         19            0    133.4kb        133.4kb
yellow open   api-nginx-access-2018.11.12 9n4sfrfFT4yCa7Kp5IFZNg   5   1      40121            0        4mb            4mb
yellow open   api-nginx-access-2018.10.31 6YxRk1kkRuWDAGDrndXApA   5   1      40941            0        4mb            4mb
yellow open   api-nginx-access-2018.10.30 bRZ_7_YeT0SZSyC0j1i7mg   5   1      38288            0      3.6mb          3.6mb
yellow open   api-nginx-access-2018.11.11 VfaS5hVKTDyFXLdjHVSecQ   5   1      35786            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.11.06  vC_QtLPmTRugJZsR7du4_w   5   1        289            0    278.6kb        278.6kb
yellow open   ap-nginx-access-2018.11.12  c97C6639SNatlNJpsVKFeA   5   1        355            0    364.2kb        364.2kb
yellow open   ap-nginx-access-2018.11.06  tV7vbxDXR_aEXwbKhWp0Sw   5   1        183            0    298.4kb        298.4kb
yellow open   api-nginx-access-2018.11.01 4UHB-q-hSCWnTaQgoDmizQ   5   1      40240            0      3.9mb          3.9mb
yellow open   api-nginx-access-2018.11.05 2Jhq-KLEQLm3HtJNrf6j6w   5   1      38685            0      3.7mb          3.7mb
yellow open   api-nginx-error-2018.11.07  99-0rOfVS42rH1vm-9CDnw   5   1        312            0    161.4kb        161.4kb
yellow open   api-nginx-error-2018.11.02  KHLZjLKRTK-wDnCLcD7Fdw   5   1        550            0    302.8kb        302.8kb
yellow open   ap-nginx-access-2018.11.02  7iB_pIGEQlygM7OQrs2CVA   5   1        136            0    230.7kb        230.7kb
yellow open   api-nginx-error-2018.11.12  Sg7P8WneQz2H_gTzwAKxfw   5   1        277            0    145.2kb        145.2kb
yellow open   api-nginx-access-2018.11.06 zwYwZHYZQcKVY90MgI3jgA   5   1      41895            0      4.2mb          4.2mb
yellow open   api-nginx-error-2018.11.08  qhH5k3cqRb-Lu9qvPh_FNw   5   1        537            0    220.4kb        220.4kb
yellow open   api-nginx-error-2018.10.30  HhB_3KPJRZe6lJBOpz9cEQ   5   1         41            0      255kb          255kb
green  open   .kibana                     -mBnXlR2QQGCuTDFEScqng   1   0         11            1     30.3kb         30.3kb
yellow open   ap-nginx-access-2018.11.04  Zh-SgjiITye2tW1krPgT0g   5   1         96            0    264.7kb        264.7kb
yellow open   api-nginx-access-2018.11.13 Ztu6V_jsTfqAx7HVcFuRNw   5   1        709            0    209.6kb        209.6kb
yellow open   api-nginx-error-2018.11.11  W44PXSWTQ9aTdE2TtMN2LQ   5   1        266            0    122.6kb        122.6kb

curator を使用した場合のインデックスリスト表示

[user@hostname ~]# curator_cli show_indices
.kibana
ap-nginx-access-2018.10.30
ap-nginx-access-2018.10.31
ap-nginx-access-2018.11.01
ap-nginx-access-2018.11.02
ap-nginx-access-2018.11.03
ap-nginx-access-2018.11.04
ap-nginx-access-2018.11.05
ap-nginx-access-2018.11.06
ap-nginx-access-2018.11.07
ap-nginx-access-2018.11.08
ap-nginx-access-2018.11.09
ap-nginx-access-2018.11.11
ap-nginx-access-2018.11.12
ap-nginx-access-2018.11.13
ap-nginx-error-2018.11.08
api-nginx-access-2018.10.30
api-nginx-access-2018.10.31
api-nginx-access-2018.11.01
api-nginx-access-2018.11.02
api-nginx-access-2018.11.03
api-nginx-access-2018.11.04
api-nginx-access-2018.11.05
api-nginx-access-2018.11.06
api-nginx-access-2018.11.07
api-nginx-access-2018.11.08
api-nginx-access-2018.11.09
api-nginx-access-2018.11.10
api-nginx-access-2018.11.11
api-nginx-access-2018.11.12
api-nginx-access-2018.11.13
api-nginx-error-2018.10.30
api-nginx-error-2018.10.31
api-nginx-error-2018.11.01
api-nginx-error-2018.11.02
api-nginx-error-2018.11.03
api-nginx-error-2018.11.04
api-nginx-error-2018.11.05
api-nginx-error-2018.11.06
api-nginx-error-2018.11.07
api-nginx-error-2018.11.08
api-nginx-error-2018.11.09
api-nginx-error-2018.11.10
api-nginx-error-2018.11.11
api-nginx-error-2018.11.12

curator を導入するに至った背景

ウィルゲート ではログ基盤として EFK ( Elasticsearch + Fluentd + Kibana ) を構築しています。

EFK を運用するにあたり、ログを絶え間なく Elasticsearch に蓄積していくためデータ量が膨大になっていき、結果的に Kibana のレスポンスが悪くなったり最悪表示ができなくなってしまうという問題がありました。

f:id:tkhttty:20181112182226p:plain

curator を導入する以前は、 古いインデックスに対して curl -XDELETE をひたすら投げるシェルスクリプトを実行して削除を行っていたのですが、古いインデックスが綺麗に削除されなかったり、 curl プロセスが大量に生成され負荷が上昇したりと運用において大きな課題となっていました。

そこで、前述した Elasticsearch の運用管理ツールである curator を利用して古いインデックスの削除を試みてみました。

導入方法

curator のインストールおよび設定には 構成管理ツールである Ansible を利用しています。

AWS の Elasticsearch へ接続する際に IAM Role を使用するため、最初に必要なモジュールである「requests_aws4auth」をインストールしてから elasticsearch-curator をインストールします。

また、curator の設定ファイルは Jinja2 テンプレートとして作成しています。

最後に 毎日 3 時に実行するように cron を設定すれば完了です。

Ansible Playbook

---

- name: install requests_aws4auth
  pip:
    name: requests_aws4auth
    state: latest

- name: install elasticsearch-curator
  pip:
    name: elasticsearch-curator
    state: latest

- name: mkdir .curator
  file: path=/root/.curator state=directory owner=root group=root mode=0755

- name: configure curator
  template: src={{ item.src }} dest={{ item.dest }} owner=root group=root mode={{ item.mode }}
  with_items:
    - { src: 'curator.yml.j2', dest: '/root/.curator/curator.yml', mode: 644 }
    - { src: 'delete_old_index.j2', dest: '/root/.curator/delete_old_index', mode: 644 }

- name: set cron curator
  cron: name={{ item.cron_name }} minute={{ item.cron_minute }} hour={{ item.cron_hour }} day={{ item.cron_day }} month={{ item.cron_month }} weekday={{ item.cron_weekday }} job={{ item.cron_job }} user={{ item.cron_user }}
  with_items: "{{ cron_list }}"

vars

cron_list:
  - cron_name: Run curator
    cron_minute: '0'
    cron_hour: '3'
    cron_day: '*'
    cron_month: '*'
    cron_weekday: '*'
    cron_job: 'curator /root/.curator/delete_old_index'
    cron_user: root

curator.yml.j2

client:
  hosts:
    - AWS ESのエンドポイント(例: vpc-kibana-xxxxxxxxxxx.ap-northeast-1.es.amazonaws.com)
  port: 443
  url_prefix:
  use_ssl: True
  certificate:
  client_cert:
  client_key:
  ssl_no_validate: False
  http_auth:
  timeout: 30
  master_only: False
 
logging:
  loglevel: INFO
  logfile:
  logformat: default
  blacklist: ['elasticsearch', 'urllib3']

delete_old_index.j2

actions:
  1:
    action: delete_indices
    description: >-
      このアクションの説明
    options:
      ignore_empty_list: True
      timeout_override:
      continue_if_exception: False
      disable_action: False
    filters:
    - filtertype: pattern
      kind: prefix
      value: 対象インデックスの接頭語(例:web-error-log-)
      exclude:
    - filtertype: age
      source: name
      direction: older
      timestring: '%Y.%m.%d'
      unit: days
      unit_count: 何日以上経過したら消すか(例:10)
      exclude:
  2:
    action: delete_indices
    :
    : 以下、対象のインデックス分追記していく
    :

導入してみて

前述したように、これまで curator ではなくシェルスクリプトから curl を投げ続けるという方法でインデックスを削除していたため、サーバの負荷が上昇してしまったり、綺麗に古いインデックスが消せずに蓄積し続けてしまうなど課題が山積みとなっていました。

今回 curator を導入してからというもの、綺麗に古いインデックスを削除しつつ全くと言っても良いほど負荷もかからないので、素晴らしくサーバ(と心の)の平穏が保たれています。

f:id:tkhttty:20181112182259p:plain

また、 curator のインストールや設定を Ansible によりコード化しているので、同様に EFK を運用している別サービスにも手軽に適用できるようになりました。

おわりに

curator を利用することにより、 AWS Elasticsearch Service に登録されている古いインデックスを綺麗に削除でき平穏が訪れてきました!

同じような悩みをお持ちの方は curator を利用してみることをオススメします!

Firebaseを利用したプッシュ通知の実装

こんにちは。メディアチームの吉田です。 暮らしニスタのアプリにFirebase Cloud Messaging(以下、FCM)を使用したプッシュ通知を導入したので、FCMの紹介と導入の経緯を説明していきたいと思います!

FCMとは

googleが提供しているメッセージを無料で確実に配信するためのクロスプラットフォーム メッセージング ソリューションです。 FCMでは管理画面上からユーザーセグメント毎の配信や個別の端末への送信ができます。 また、アプリケーション側からFCMのAPIを叩くことで任意のタイミングでプッシュ通知を送信できるようになります。

暮らしニスタのアプリにプッシュ通知を挿入した背景

暮らしニスタのアプリには以前から、プッシュ通知を送信する仕組みは導入されていました。しかし、全端末に同じ内容の送信しかできず、個人向けの通知を送ることができませんでした。 そこで、個別のプッシュ通知を送信できる仕組みの導入を行うことになりました。 暮らしニスタにはステキやコメントといった機能があり、アプリ内の通知欄には投稿した記事にコメントやステキがつくと通知が届くようになっていました。これらの通知をアプリを使っているユーザーにはプッシュ通知でお知らせすることにしました。

導入方法

FCMにはFirebase Console上で送信する方法と、APIを利用した方法の2種類があります。 Firebase Console上から送信する方法の場合、アプリ側の実装のみで送信や、開封率の取得ができるようになります。 APIを利用した方法の場合、アプリ側とアプリケーション側の実装が必要になりますが、APIで送信ができるので任意のタイミングで送信することができるようになります。一方で、開封率などは取得できないでの独自で実装する必要が出てきます。

今回の実装は、一斉送信する際は、Firebase Console上から送信する。個別のプッシュ通知はAPIを使って実装する方針に決まりました。

アプリケーションサーバーからプッシュ通知を送信する

Webアプリケーション側からプッシュ通知を送信する際にはトークンの情報が必要なので、起動時とログイン完了時にトークンを取得するようにしました。そのトークンの情報とユーザーIDを紐付けて送信する際に使用します。

単一端末へのプッシュ通知の送信

単一端末への送信は下記のようにして送信ができます。トークンと本文を設定することで送信をおこなうことができます。暮らしニスタでは通知の配信と同じタイミングで送信をするように実装しました。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "notification" : {
    "body": "通知本文",
  }
}

データをアプリに渡す

プッシュ通知を送信する際にデータをアプリ側に渡すことができます。 暮らしニスタの場合、プッシュ通知を開封した際に、開くページを変える必要がありました。 そこで送信の際に開くページを一緒に送信し、アプリ側で開封の際に開くページを変更する実装を行いました。 dataの中で送信した値をアプリ側で取得することができます。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "data": {
    "openUrl": "/articles"
  },
  "notification" : {
    "body": "通知本文",
  }
}

画像付きアプリケーションを送信する

iOS10以降では通知に画像をつけることができるようになりました。 FCMでは画像付きのプッシュ通知を送信することもできるようになっています。 データの送信と同様にdataの中で画像のurlを指定します。そしてmutable_contentにtrueを入れて送信します。 アプリ側ではNotification Service Extensionを使って受信した際に画像を表示する実装をおこないます。 f:id:yoshhhy:20181107112123p:plain

f:id:yoshhhy:20181031173845j:plain

最後に

FCMを使用することで簡単にプッシュ通知を送信できるようになりました。 一斉送信はもちろん、APIを用いることで個人あてのプッシュ通知の送信も実装ができるので、プッシュ通知を導入する際にはFCMを使ってみてはいかがでしょうか。

「Hacker's GATE LT & 交流会 #2」を開催しました!!【写真あり】

こんにちは!2018年新卒エンジニアの田島です。

今回は10月25日に開催された「Hacker's GATE LT & 交流会 #2」の模様をお届けしたいと思います!

Hacker's GATE とは

ウィルゲートでは、毎月1回「Hacker's GATE」という名称で社内勉強会を行っております。

最近では社内にとどまらず、社外の方をお招きしてのイベントも開催してきました。

tech.willgate.co.jp

tech.willgate.co.jp

前回のイベントからは connpass でイベントページを開設し、幅広いフィールドのエンジニアの方々と交流しています!

willgate.connpass.com

「Hacker's GATE LT & 交流会 #2」の様子

今回のテーマは「新卒入社『約』3~5年目のホンネ」ということで、お集まりいただいた発表者のみなさまに様々な「ホンネ」を語っていただきました!

f:id:tajima-ryo:20181030094805j:plain

f:id:tajima-ryo:20181029105150j:plain

f:id:tajima-ryo:20181029185524j:plain

f:id:tajima-ryo:20181029105253j:plain

f:id:tajima-ryo:20181029104951j:plain

同じエンジニアといえど辿ってきた道は千差万別。一つの業務を経て得た知見から様々な働き方のお話まで、どの LT も様々な観点から作られたバラエティに富んだ内容で、皆さんとても興味深く聞き入っている様子でした。

f:id:tajima-ryo:20181029105325j:plain

f:id:tajima-ryo:20181031153021j:plain

f:id:tajima-ryo:20181029185028j:plain

また、交流会も終始和気藹々とした雰囲気で進行し、活発な交流の場となっていました。

LT 会に参加して下さった方も、LT をしていただいた方も、本当にありがとうございました!

最後に

今後も Hacker's GATE 運営では、社外への発信を目的として LT 会や交流会を開催していく予定です。 LT をしたいという方はもちろん、色々な方の LT を聴きたい、様々な人と交流したいという方も歓迎です!

またウィルゲートでは「Hacker's GATE もくもく会」と題して、毎週木曜日にもくもく会の開催を行なっております。 こちらも参加者募集中となっておりますので、よろしくお願いいたします!

willgate.connpass.com

皆様のご参加を、心よりお待ちしております!

画面制作(html, css)をエンジニアが行うようになってからの課題と取り組み

暮らしニスタのPMを担当しているウィルゲートの水口と申します。 暮らしニスタの開発チームでは、2016年のリニューアルリリース以降、画面のコーディングをエンジニアが行っています。今ではスムーズに開発ができていますが、最初はうまくいかなかった事もありました。今回はエンジニアが画面コーディングを担当するようになってからの問題点と、これまでどう改善してきたかについて紹介させていただきます。

リニューアルまでの制作フロー

f:id:mizuguchi-harumi:20181010194019p:plain

デザイナー(制作会社など)からHTML、CSS(scss)を受け取り、エンジニアはフレームワークへの反映のみ行っていました。

リニューアル以降の制作フロー

f:id:mizuguchi-harumi:20181010194030p:plain

デザイナーはデザインまでを担当、エンジニアがHTML、CSS(scss)をコーディングするようになりました。

エンジニアが画面制作するようになってからの問題点

画面制作スキルのバラツキ

ほとんどのエンジニアが画面コーディングを担当してなかったので、メンバーごとに画面コーディングの得意不得意がありました。はじめはフロントが得意なエンジニアに画面制作の担当を寄せていましたが、それだけでは工数が足りないこともありました。ただし不得手なメンバーが担当すると、工数がかかってしまい、全体的な開発コストが膨らんでしまっていました。

デザインの連携

一部を除いてエンジニアは高機能なデザインソフトを持っていません。デザインコーディングに必要な色、サイズ等の詳細な設定値を図る方法が確立されていなかったため、デザインの把握に時間がかかっていました。

修正・手戻りの発生

デザインの連携が上手くいかなかったこと、制作に慣れていないなどが影響して、制作後のレビューとその修正に膨大な時間がかかっていました。また、画像では伝わらない画面動作等の動的な部分について、後から指摘を受けることもあり、手戻りが沢山発生していました。

上記のような問題が半年くらい続き、デザイナーも含め、メンバー間の協力体制も揺らぎかけてきました。
もっとスムーズに開発が進められるように、デザイナー、フロントエンジニアを中心にチームで改善を行ってきました。

現在のフロー

f:id:mizuguchi-harumi:20181010195008p:plain

フローと担当者は変わっていませんが、連携方法が変わりました。

改善したポイント

デザイン連携にZeplinを導入

以前は画像での連携でしたが、Zeplin(https://app.zeplin.io)というツールを使うようにしました。 このツールの導入により、デザインコーディングの制作工数と手戻りが減少できました。 ZeplinはSketchデータから簡単に作成でき、連携に使える機能が色々あります。

①要素の設定値が表示される

コーディング時に必要なサイズや色等の設定値が表示されます。 f:id:mizuguchi-harumi:20181011201106j:plain

②スタイル属性値の自動生成

ある程度の表現は自動で出力されるので、コーディング時に細かい属性を考えなくても良くなりました。

③コメント機能

Zeplinは画面にコメントをつけることができます。 デザイン画像からは判断できない事などデザインの不明点を書いたり、制作後レビューのフィードバック連携にも利用しています。 f:id:mizuguchi-harumi:20181011201113j:plain

デザインパーツの共通化

デザインの体系化・デザインガイドライン作成

ページ毎、エリア毎にデザイン制作が行われていたため、サイト内に様々なデザインが混在していました。似たようなデザインなのに、要素が統一されていないため、バラバラにCSSをコーディングする状態になっていました。
デザイナー中心にガイドラインの整備を行い、色、文字サイズ、間隔等設定値の整理からはじまり、ボタン、見出し、リスト等のデザインについても統一されました。
今では各ページのデザインについても体系化されたデザインに沿って作成されるようになっています。

スタイルガイドの整備

フロントエンジニアを中心に、CSSの構造の見直しと、体系化したデザインをもとにスタイルガイドを整備しました。

設定値の共通化(色、文字サイズ等)
f:id:mizuguchi-harumi:20180903133317p:plain

パーツ(ボタン、アイコン、画像等)の共通化
f:id:mizuguchi-harumi:20180905165656p:plain

レイアウト(グリッドシステム等)の共通化
f:id:mizuguchi-harumi:20180903134746p:plain

リスト型のレイアウトやグリッドシステムについても共通化され、楽にレイアウトを表現できるようになりました。

デザイン共通化によって、同じようなデザインを何度も書くと言うことが減りました。また、必要なコーディング量が減ったので、画面制作が得意ではないメンバーもスムーズに画面を作ることが可能になりました。

コミュニケーションの増加

デザイナーとエンジニア間でデザインの要件や意図の連携がうまくいかず手戻りが発生したり、デザインのコーディングの難易度が高すぎて、最初の見積りより工数がかかってしまうことがありました。
デザイン制作前に要件と方向性の確認し、画面制作に取り掛かるまえから認識齟齬を減らすようにしています。また、デザインコーディングの前や途中でも、密にコミュニケーションをとり、コーディングの難易度が高すぎる場合に簡単な表現に変更できないか、デザインガイドラインから離れている箇所があれば統一できないかなどの実装上の相談を都度行うようにしています。

最近の課題

これまではデザイナーが常に社内にいることが多かったのですが、最近ではデザイナーがリモートにいる事が増えてきました。基本的にはSlackで連携していますが、文字では伝わりにくい場合は、電話やSlackの動画チャットを使うようにしています。

まとめ

今回はエンジニアがコーディングを担当するようになってからの問題とどのように改善してきたかについてご紹介しました。
改善を通して、エンジニアメンバーが画面制作をスムーズに行えるようになりました。その結果、デザイナーはデザインに専念することができ、エンジニアも画面制作以外の開発にも時間を避けるようになり、チームの全体の生産力向上につながったと感じています。

Embulkを活用してAmazon Elasticsearch Serviceへデータを同期させた話

こんにちは。インフラチームの高畑です。

今回は Elasticsearch (ES) を AWS に移行した際に導入した Embulk についてお話しします!

Embulkとは

Embulk とは、 Fluentd の開発者である古橋貞之氏によって開発された、 Fluentd のバッチ版のようなものです。 プラグインにより、インプットとアウトプットを柔軟に切り替えることが可能となっており、バルク処理に特化しています。

Fluentd と Embulk の違い
Fluentd
  • データのストリーミング転送
  • 既存の大量なデータは転送ができない

Embulk
  • 定期実行によるデータ転送
  • 分散処理により既存の大量なデータを転送できる

Embulkで利用できるプラグインは以下の通りとなっています。

プラグインの一覧はこちら

Input Plugin RDS、S3、GA、ES・・・・・
Output Plugin RDS、S3、GA、ES・・・・・
Filter Plugin カラムを削ったり、再構成したり
File Parser Plugin
File Decoder Plugin
File Formatter Plugin ファイル関係
File Encoder Plugin
Executor Plugin Hadoop上で実行させたり

導入前

これまで、サービスで利用する ES を自前で構築し、JDBC ドライバを利用して RDS から ES に対しデータを転送していました。 また、ログ基盤として EFK (ES + Fluentd + Kibana) をAWS のマネージドサービスを用いて構築を行なっていました。

サービスで利用する ES を AWS ES に統一しようと考えていたのですが、AWS ES は JDBC を利用したデータ転送が出来ないという問題があり、サービス用の自前 ES とログ基盤用 AWS ES が混在するという無駄な状態となってしまいました。

そこで、これらを解決するため、JDBC での転送をやめ Embulk を利用してデータ転送を行うことにしました。

f:id:tkhttty:20181005143003p:plain

導入後

Embulk の設定ファイルはとてもシンプルな構造となっており、 RDS からデータを取得して ES へ送るだけであれば以下のように設定するだけで動作します。

(括弧で括っているところは環境に応じて変更する必要があります)

f:id:tkhttty:20180921164109j:plain

Embulkを活用して 1 日 1 回の同期処理をさせることにより、AWS ES に RDS のデータを流せるため、自前の ES は不要になり ES の混在状態を解消することができました。

またこれにより、自前で ES を管理する必要がなくなり運用コストの低下にもつながりました。

f:id:tkhttty:20181005142043p:plain

おわりに

Embulkを活用することにより、自前で構築していたESを使う必要がなくなり運用コストの削減に繋げることができました。

同様なことで悩んでいる方がいらっしゃいましたらぜひ活用してみると良いかと思います!

アプリもくもく会を開催して感じたこと

はじめに

こんにちは。ウィルゲートで開発を行っている三島です。 私の所属するメディアチームでは「暮らしニスタ」や「Milly」などのメディアサイトの構築と運用を行っています。また、webサイトだけでなくwebViewではありますが、スマートフォンアプリの開発も行っています。

今回はメディアチームでアプリについて学ぶ時間として開催している「アプリもくもく会」について紹介していきます。

f:id:MikaE:20180906214635j:plain

もくもく会を開いた背景

アプリ開発は2016年から行っていますが、ウィルゲートではこれまでwebサイト構築を主に行ってきたため、アプリ開発についての知見がありませんでした。 これまではwebViewのアプリであったため、ネイティブアプリに比べ開発難易度が低く、なんとか調べながら開発を行っていくことができていました。

アプリができてから2年ほど経ち、アプリを使ってくださるユーザーが増えてきたため、 更に使いやすいアプリにするために、アプリをネイティブ化することが決まりました。

ネイティブアプリはこれまで作成してきたwebViewのアプリよりも難易度が高く、知らないことが多いです。そのため、これまでのようにトライアンドエラーを繰り返すことは効率が悪いと感じていました。 アプリ開発を1から調べながら学ぶことは効率が悪いため、ウィルゲートでは社外のネイティブアプリ開発に知見を持っている方にアプリの技術顧問として入っていただけることが決まり、アプリ開発についておしえていただけることになりました。 技術顧問についての詳細は下記の記事を見てください。

tech.willgate.co.jp

ネイティブ化に向けて技術顧問の方に入っていただき、アプリ開発における疑問点は解消できていますが、今後webViewからネイティブへ移行することでこれまでよりもアプリの保守工数が増加することが見込まれています。 しかし、現在チーム内でアプリの開発を行っている人が私以外にいないため、必然的に対応できる人も1人です。今後アプリを開発保守していくためにも、チームとして技術の底上げが必要だと感じていました。 チームとして技術を底上げするためにアプリについて学ぶ時間を作る必要があると感じていました。アプリについて学ぶ時間として勉強会やもくもく会などがありますが、メディアチームではもくもく会を開催することにしました。

勉強会ではなくもくもく会を開催することにした理由としては以下の2点です。

  • 勉強会の形式にもよりますが、もくもく会のほうが実際に自分でコードを書く時間が多く各自のレベルに合った勉強ができる
  • 各自で勉強をしてもいいが、勉強するためには強い意志が必要になるので集まって勉強をしたほうが続きやすい

もくもく会でやっていること

もくもく会では一般的なもくもく会と同じように時間が空いた人が集まって個人でアプリについて学ぶ場にしています。 ただ漠然とアプリについて調べたり、コード書いたりするだけでは効率が悪いので、mixiさんのiOSTrainingやAppleのswiftのチュートリアルなど基礎的なことを学ぶ事ができる資料を見ながら勉強しています。

iOSTrainingはXcodeの使い方やSwiftの書き方など基礎的なところから学ぶことができるため、初心者の方におすすめできる資料だと思っています。

GitHub - mixi-inc/iOSTraining: Training course repository for iOS app developmentgithub.com

Appleのswiftのチュートリアルは英語で書かれているため読むことに時間がかかってしまいますが、簡単なCRUDのアプリを作ることができるため、楽しく学ぶ事ができるのでおすすめです。

developer.apple.com

もくもく会の感想

良かったこと

良かったこととしては、チュートリアルを進めていくことで基礎的な力はついたと感じています。また、これまで1人で勉強をしていたため疑問の解消に時間がかかっていましたが、チームで勉強を行うことで他の人に質問をすることができ、より効率よくアプリ開発について学ぶことができています。特にこれまで1人で調べ1人で解消していたため孤独を感じていましたが、雑談しながら勉強することで楽しく勉強ができ良かったと思います。 時間を作って参加してくれたチームメンバーには感謝しか無いです。

反省点

チュートリアルをこなすことで基礎は学ぶ事ができたと思いますが、実際のプロダクトコードでは応用が求められます。もくもく会チュートリアルで学んだことを実際に使ってみることができなかったです。今後は実際に題材を決めアプリを作ってみるなど応用を学ぶ事ができるように工夫していきたいです。

まとめ

アプリもくもく会を始めて3ヶ月経ち、全体として基礎的な知識はついてきたと感じています。 今後こういった活動を続けていくことで、ウィルゲートの開発組織全体としてwebアプリだけでなくネイティブアプリを開発できるようになり、より多くの人にサービスを利用してもらえるようにしていきたいです。