オールアバウトTech Blog

株式会社オールアバウトのエンジニアブログです。

2020年の年末LT会はオンラインで開催しました

はじめに

こんにちは!オールアバウトナビ、システム部の@k_shiotaです。

昨年の年末、 2020年を締めくくるべく年末LT会を行いました。
基本リモートワークとなるため、当日はオンラインでの開催となりました。
今回はその様子をお伝えしたいと思います。

続きを読む

2020年に開催した社内ワークショップまとめ

この記事は、All About Group(株式会社オールアバウト) Advent Calendar 2020 17日目の記事です(大遅刻申し訳ありません!)

@amymdです。そろそろ2020年も終わりに近づいてきましたね。
今年は新型コロナの影響でリモートワーク中心の働き方に変わった一年になりましたが、定期的に開催しているエンジニア向けワークショップもリモートで開催されるようになりました。そこで、今年社内で開催されたワークショップについてまとめて報告したいと思います!

  • 1.新しくなった開発環境とこれから
  • 2.今回のコロナ対策とそこから見えてきたもの
  • 3.チームごとの振り返り
  • 4.オールアバウトのネットワーク構成
  • 5.「最近何やってるの?」LT
  • 6.データポータル見せ合う会
  • 最後に
続きを読む

初のフルリモート体制で新卒が素直に書く! ~新卒でオールアバウトナビに配属されて~

はじめに

こんにちは!オールアバウトナビ(以下からナビで省略します)システム部に新卒入社した@monpeiです。

今年就職された方は同年代のエンジニアがどんなことをやっているか気になりませんか?また、来年就職される方や現在就職活動中の方、来年からの仕事に不安を感じていませんか?

私は入社前福島にある大学に通っていましたが、東京で一人暮らしをすることが決まり、不安と期待が高まっていました。 しかし4月からフルリモートの社会人生活のスタートが近づくにつれ、不安の方が強く感じるようになりました。 「どんな社員がいるんだろう?」、「コミュニケーション取れるのかな?」、「業務について行けるかな?」など頭を過ぎっていました。

今回は本配属から半年を経てどのような業務をしたか、コミュニケーション不足・モチベーション低下の解消のためにやっていることについてお話します。少しでも共感する部分があったり、不安を抱えている方が少しでも解消いただける内容になっていれば幸いです。

ベテランの方でも「新卒って何考えてるんだろう〜?」位な感じで読んで頂ければと思います。

ナビの詳細は下記のリンクからご確認いただけます。 www.allaboutnavi.co.jp

4月から現在までのやったこと

4~6月末 研修

主にgitや社内で使用している言語やフレームワークなどについて学びました。

下記リンクから新卒研修の詳細が確認できますので、ご興味ある方はご一読ください。 about.allabout.co.jp

ナビに本配属、業務スタート

7月〜8月初旬

配属されて初の作業は、ローカル環境で開発を進めらるようにDocker環境の構築をしました。 続いてDocker環境構築後に、弊社のウェブサイトやcmsの軽微な修正や機能追加、広告のタグ差し替えなどを行いました。 修正の内容はサイトから一部リンクを削除と新しいリンクにリダイレクトするというとても簡単なものでしたが、初リリースができた時は非常に嬉しかったです。

8月中旬〜10月初旬

業務にも段々と慣れ始め、任されるタスクも少しずつですがレベルが上がってきました。 以下のようなプログラムを作成しました。

  • GKE上で動くバッチ処理(CronJob)で定期的にデータベースのレコードに変更を加える
  • 自動で毎日決まった時刻にCloud Functionsを実行し、Node.jsを用いて集計対象のサイトへスクレイピングをかけ、取得したデータをレポートとしてスプレッドシートに書き込む。

10月中旬〜現在

主なトピックとしては使用しているフレームワークをLaravelに変更するため動いています。 また開発ではありませんが、Team Tech Ballというエンジニアのためのエンジニア主導の組織横断チームに加入しました。

今までの振り返り

業務で実装した集計の自動化の話

背景

では続いて私が業務で実装した集計の自動化の話です。 弊社サービスの一つであるcitrusは外部ニュースサイトにもフィードを行っており、そのフィード先での記事のタイトルやpv数などのデータを集計する作業がありました。 一回の集計作業にかかる時間はさほどかかりませんが、毎日行う必要があり長い目で見ると時間がかかるため、集計の自動化をすることになりました。

citrusの詳細は下記リンクからご確認いただけます。 citrus-net.jp

実装内容

以下今回のタスクの条件です。

  1. 毎朝指定の時間に処理を実行する
  2. フィード先の管理画面(集計するデータが閲覧できる)にログインし、データを取得する
  3. 取得したデータを集計専用のスプレッドシートに追加する

上記の条件を実装する方法はいくつか考えられましたが、今回は下記のような実装を行いました。

f:id:allabout-techblog:20201214092059p:plain
集計自動化のフロー

ナビでは集計の自動化でCloud FunctionsとNode.js + Puppeteerで動いているプログラムがあり、その前例が役立つと考え、これらの技術を選定しました。また、私自身がCloud FunctionsやNode.jsはほとんど使用したことがないことから、自分のスキルアップにも繋がり、ありがたかったです。

流れとしてはCloud SchedulerがCloud Pub/Subを介してCloud Functionsを起動させます。 次にCloud Functionsがフィード先の管理画面にログインし、スクレイピングをかけデータを取得します。 最後に取得したデータをCloud Functionsを用いてスプレッドシートに追加し処理が終了します。 Cloud FunctionsはNode.jsで動いており、スクレイピングはPuppeteerというライブラリを用いています。

Cloud Scheduler

https://cloud.google.com/scheduler/docs/quickstart

Pub/Sub トリガーのCloud Functions

https://cloud.google.com/functions/docs/calling/pubsub?hl=ja

Puppeteer

https://github.com/puppeteer/puppeteer

所感

使用した技術はどれも初めて使うものだったので調査や慣れるのに少し手こずりましたが、自分が知らなかった技術を学ぶことができ、自分が開発で使える選択肢を増やすことができました。 Cloud Functionsはサーバレスアーキテクチャのため、サーバーを立てる処理がいらないことが非常に便利だと感じました。

また、自動集計の実装後に社員から「業務効率が上がった」、「ありがとう」などと言ってもらうことができ、非常に嬉しく思いました。

フルリモートの環境に慣れるまで

コミュニケーションが取りづらい、自宅作業でモチベーションが上がらない時が多々あった

今年はコロナの影響を受けて働き方に大きな変化があった年だと思います。 リモートワークは一長一短かと思いますが、私はコミュニケーションのとりずらさに戸惑いを感じたり、思っていたよりも他の社員との関わりが少なかったことから不安を感じたりしました。 また在宅で仕事へのモチベーションの維持が難しかったり等、慣れるまで少し時間がかかりました。 特に私と同様に今年新卒の方であれば共感していただける部分があるのではと思います。 自分なりにどうやって、コミュニケーション不足を解消したか、また仕事へのモチベーションを上げた取組をいくつか紹介したいと思います。

コミュニケーション不足解消、モチベーションを維持するためにやったこと

前述で触れましたが10月にTeam Tech Ballというエンジニアのためのエンジニア主導の組織横断チームに加入しました。 Team Tech Ballに関しては下記の記事に詳細が記載されています。よろしければ合わせてお読みください。 allabout-tech.hatenablog.com 加入を決めた理由は沢山あるのですが、決め手になったのは二つです。 一つ目は現在ナビのエンジニアは私含め二人しかおらず、エンジニアとの接点が少ないことです。 加入することで、他のグループ会社のエンジニアと関わってコミュニケーションをとりたい、技術的にスキルアップしてできることを増やしたいと強く感じました。

二つ目は、自分がベンチマークにしていた方がTeam Tech Ballに所属していたためです。 私は最新の技術を突き詰めることよりも、自分の仕事や作ったもので誰かが喜んでくれたり、感謝してもらえるようなエンジニアでありたいと考えています。 ベンチマークにした方は、リーダーシップがあり、マネジメント能力が高く、常に誰にでも親切な方です。 「10年後あの人みたいになりたい!少しでも近づきたい!」と思える人と一緒に仕事をすることでモチベーションが上がりました。 まだまだその方に追いつくには技術的にも人間力的にも先が遠いので精進したいと思います!

現在はナビの業務とは別に、Team Tech Ballの活動の一貫で、社内のエンジニアの勉強・交流会の企画や、自社内の勉強会などのイベントを管理するツールの作成を行っております。 中々はじめは業務上関わる人が少なくコミュニケーションが取りづらいと、もやもやしておりました。 自分から新しいことにチャレンジする、新しい環境に飛び込むことで、以前より仕事への充実感が増してきたのを感じています。

新しいことや環境にチャレンジしたり、飛び込むことは勇気がいることですが、それをしなくてはいけない環境に身をおいてしまえば、案外何とかなることが多い気がしております。 こんな時期こそチャレンジ精神を忘れずにがむしゃらに突き進んで行きたいと思います!

ナビシステム部内での取組

続いてナビシステム部内で毎日行っている朝会についてお話します。 ナビのシステム部内では上期の途中から他の開発部署の取組や業務の仕方を積極的に取り入れ、日々業務の仕方を改善しております。 その中でも、上期の終わりくらいから朝会を導入したのですが、私のモチベーションを上げた要因の一つでしたのでご紹介できればと思います。

以前ナビでは業務終了前の夕会しか行っておらず、話す内容も進捗度合いの報告がメインで、どこに悩んでいたのか、悩み中なのか等を共有する時間を設けてはいませんでした。 私の部署の先輩方は非常に優しく、質問や相談をしやすい環境にはあったものの、リモワの場合相手がどんな状況にあるかが把握しずらく質問や相談をするハードルが高いと感じておりました。 そんな中、上期の途中から毎日業務開始後すぐの15分位を使って朝会を始めました。 朝会を通してその日やることの共有と、前日やったことをjamboardを使って簡単なモチベーショングラフを書き、共有を行っています。

以前よりどこに悩んでいたのか、悩み中なのかが共有しやすくなり、話すことで自分だけで抱え込まずにすむため気持ちが楽になりました。またメンバーの状況もよく把握できるようになりました。他のメンバーがどのくらいのタスクがあって、どこに悩んでいるのかなどの状態も把握しやすくなり、「〇〇さんのタスク僕が巻き取ります!」などが言いやすくなりました。

また朝会ではありませんが、金曜日に行っている振り返りでは、技術の話だけでなく雑談を交えながら次週チャレンジすることを話しています。 このような取組をきっかけに、メンバーとの距離感もわかってきて質問や相談が非常にしやすくなりました。 ぜひコミュニケーションが不足していると感じたチームは朝会を導入してみてはいかがでしょうか?

最後に

本配属から半年を経て私が大事だと感じたことは大きく二つあります。

一つは日々の業務を流れ作業にしないことです。 業務を覚える、できることが増えるようになることは良いことですが、その反面慣れも出てきてミスをする恐れもあるということを学びました。 月に一度は自分を見直す時間を設け、できるようになったことと、慣れが出てきた部分を洗い出してみようと思います。

二つ目はコミュニケーションは大事だということです。 当たり前のことを書いておりますが実体験として、コミュニケーションが不足すると、長い目で見たときに実装の進捗具合に遅れがでたり、モチベーションの低下に繋がることを実感しました。 リモートワークでもコミュニケーション不足にならないようにしながら、リモートワークだからこそできる仕事の仕方を模索したいと思います。

最後まで読んでいただきありがとうございました。少しでも皆様のお役に立てる記事になっていれば幸いです。

golangでCloud Monitoringのデータを元に稼働率を取得するようにした話

こんにちは!オールアバウト SREG@y_hideshi です。

今回はGCPのモニタリングサービスであるCloud Monitoringのデータを元に稼働率を取得するようにした話をしたいと思います。

背景

オールアバウトでは、Cloud MonitoringのUptimeCheckという機能を利用してURL監視やサービスの稼働率をチェックしています。

f:id:allabout-techblog:20201026114142p:plain
Cloud Monitoring:UptimeCheckの画面

上記の画像にある通り、URL単位で稼働率を画面上から確認することができます。ただ、UptimeCheck数が多くなると、各画面に遷移して稼働率を確認するのは大変になります。

そのため、このチェックを自動化しようというのが今回稼働率を自動取得しようとした背景です。

Cloud Monitoringのデータ取得はCloud Monitoring API経由で取得することができ、Cloud Monitoring APIを扱う場合はgolangで便利なパッケージが提供されているので今回はそちらを使用します。

続きを読む

インフラに詳しくないエンジニアがGKE上でRedash環境を構築した話

はじめに

こんにちは!オールアバウトのデータエンジニア@ondaljhです。
データエンジニアをやっているものの恥ずかしいながらインフラにはそこまで詳しくない自分が、GKE上でRedash環境を構築したのでその経緯とやったことを紹介します。この記事を通して、GKEの概要とRedashをGKEで構築する1つの知見が皆様の役に立てば幸いです。

従いまして、この記事は下記のような方を想定して書かせていただきます。

  • GKEに興味はあるがインフラには詳しくないエンジニア
  • GKE上でRedash環境を構築してみたいエンジニア

※この後はRedashの導入背景やdocker-composeを使ってのローカル環境構築の話をさせていただきます。ともかくGKE上でのRedash構築の話をお読みたい方は「GKEへのチャンレジ」へ進んでいただければと思います。

なぜRedashなのか

まず、なぜRedashを導入することになったのかの話を少しだけさせていただきます。

新しい軸のデータ要望

オールアバウトはPrimeAdというコンテンツマーケティングプラットフォームサービスを提供しています。PrimeAdの計測データはすでにAllAboutReportingという、自社制作の広告集計計測サービスで確認できるようになっています。
ある日、ある部署からAllAboutReportingではまだ提供していない軸でのデータが欲しいとの要望がありました。普段ならアドホック的なデータ抽出は順次対応していましたが、今回の要望はAllAboutReportingのように、日毎のデータが常に確認できてほしいとのことでした。話をシンプルにするために、この時点での状況をまとめると下記のようになります。

  • 新しい軸でのデータ要望があった。
  • 日毎のデータが常に確認できる必要がある。
  • この軸のデータをAllAboutReportingへ追加する前にプロトタイプとして試してみた方が良いと判断した。

この状況を踏まえて、新しい軸のデータはBIツールにて提供することにしました。

BIツール選定

BIツールといっても、世の中色んな種類のBIツールがあり、どれを使えばいいのかは皆さんにとっても悩みどころだと思います。
幸い、チーム内ではすでにGoogleのデータポータルも使っていたので、今回もデータポータルで良いのでは?と思いましたが、データポータルには下記の問題がありました。
データポータルのデータソースとしてMySQLを利用する場合、データポータルのドロップダウンリストで利用するカラムの値が日本語である場合、最大20個しか使えず、それ以上の項目は「その他」として丸められる。
※ここでのMySQLはCloudSQLではなく、GCE等で自前で構築したMySQLになります。弊社の集計データとCloudSQLは相性悪く、やむを得ずGCEでMySQLをインストールして使っている状況です。

今回の要望としてはドロップダウンリストは必須で、そこで使うデータは日本語で数百~数千件に至ることはわかっていたので、今回、データポータルは除外せざるを得ないことになりました。

その故、無料で使えるBIツールを改めて調べてみることにしました。その結果上がってきた候補は下記3つで、それぞれのメリットデメリットはあうものの大差はなかったので、前から使ってみたかったRedashを試してみることになりましたー(;・∀・)

  • Redash
  • Superset
  • Metabase
    ※それぞれのBIツールのメリットデメリット等は比較記事がたくさんあるので、この記事では割愛させていただきます。

Redashのアーキテクチャ

f:id:allabout-techblog:20201015132315p:plain
Redashのアーキテクチャ

自分が認識しているRedashのアーキテクチャーは上記の図のようなものです。
これをGKE上にどうやって構築するか、を試す前に、自分のローカル環境でとりあえず構築してみることにしました。

ローカル環境での試し

Redashもdocker-composeもあんまり知らなかったので、とりあえずローカル環境での構築は下記サイトを参考にしました。
[ データ可視化ツール]RedashをDocker上で構築してRedshiftへ接続する

上記サイトにも手順がありますが、ここからは実際に自分が行った際の手順になりますので、ご参考になれば幸いです。

  • Redashリポジトリをクローンする
  • プロダクション用docker-compose.ymlを取得する
  • redash.envファイルを作成する
  • docker-composeを使ってアプリケーション全体を起動する
  • localhost:8080へアクセスする

Redashリポジトリをクローンする

git clone https://github.com/getredash/redash.git

クローンしてくるといくつかのディレクトリも生成されていることが確認できます。すべてのディレクトリ構成はリポジトリ元を参考していただくこととして、以降の説明に出てくるディレクトリ構成だけ簡単に載せますと下記のようになります。

/redash # 作業ディレクトリルート
/redash/setup # 設定ファイル等が格納されてる

また、ここで取得したdocker-compose.ymlファイルは開発専用のものであるため、プロダクション用を取得する必要があります。

プロダクション用docker-compose.ymlを取得する

get clone https://github.com/getredash/setup.git
  • 「/setup/data」ディレクトリにdocker-compose.ymlファイルがあることを確認する

docker-compose.yml

version: "2"
x-redash-service: &redash-service
  image: redash/redash:8.0.0.b32245
  depends_on:
    - postgres
    - redis
  env_file: redash.env
  restart: always
services:
  server:
    <<: *redash-service
    command: server
    ports:
      - "5000:5000"
    environment:
      REDASH_WEB_WORKERS: 4
  scheduler:
    <<: *redash-service
    command: scheduler
    environment:
      QUEUES: "celery"
      WORKERS_COUNT: 1
  scheduled_worker:
    <<: *redash-service
    command: worker
    environment:
      QUEUES: "scheduled_queries,schemas"
      WORKERS_COUNT: 1
  adhoc_worker:
    <<: *redash-service
    command: worker
    environment:
      QUEUES: "queries"
      WORKERS_COUNT: 2
  redis:
    image: redis:5.0-alpine
    restart: always
  postgres:
    image: postgres:9.6-alpine
    env_file: redash.env
    volumes:
      - /opt/redash/postgres-data:/var/lib/postgresql/data
    restart: always
  nginx:
    image: redash/nginx:latest
    ports:
      - "80:80"
    depends_on:
      - server
    links:
      - server:redash
    restart: always

ご覧の通り、docker-compose.ymlにはredashのserverはもちろん、nginxやredis等、アーキテクチャー図に登場する複数のサービスが定義されています。

redash.envファイルを作成する

ビルド時に利用する設定情報をredash.envファイルへまとめておきます。中身は下記サイトを参考にしました。必要に応じて各情報を書き換えていただければと思います。
redash-hands-on

REDASH_HOST=http://localhost
PYTHONUNBUFFERED=0
REDASH_LOG_LEVEL=INFO
REDASH_REDIS_URL=redis://redis:6379/0
REDASH_DATABASE_URL=postgresql://postgres@postgres/postgres
REDASH_COOKIE_SECRET=redash-hands-on
REDASH_SECRET_KEY=redash-hands-on
POSTGRES_PASSWORD=
POSTGRES_HOST_AUTH_METHOD=trust

docker-composeを使ってアプリケーション全体を起動する

まずは下記コマンドを使ってredashで利用するデータベースを作成します。

docker-compose -f docker-compose.yml run --rm server create_db

次は、下記コマンドを使ってアプリケーションを起動します。

docker-compose -f docker-compose.yml up -d

エラーメッセージなどが出なければとりあえず環境構築はできたことになります。

localhost:8080へアクセスする

自分はredash.envファイルでREDASH_HOSTを「http://localhost」にしたので、ブラウザを開いて「http://localhost:8080」へアクセスを試しました。

f:id:allabout-techblog:20201007122419p:plain
redash初期設定画面

できた!!ブラウザ上に上記のような初期設定画面が表示されたら、ローカル環境でRedashが構築できたことになります。

GKEへのチャレンジ

ローカル環境ではdocker-composeを使って簡単にredash環境構築ができました。が、問題はこれからです。ご存じの方も多いと思いますが、docker-composeコマンドはあくまでもdockerコマンドであり、gcloudやkubectlのようなGCP向けのコマンドではないです。つまり、ローカル環境を構築した手順のままではGKEへの構築ができない!ということになります。ローカル環境構築はredashのアーキテクチャーを理解する勉強になったので、ここからはGKE上でredashの各サービスを起動するために行ったことを紹介させていただきますー

インフラ構成

まずは詳細説明に入る前に、ローカル環境とGCP上のアーキテクチャーを比較することで全体図を把握しましょうー

ローカル環境のマニフェスト(docker-compose.yml)を見るとわかるように、Redashを構築するには複数のインフラサービスが必要になります。ここでは、ローカル環境で登場するサービスがGCP上ではどう変わるのかを表でまとめてみました。

ローカル環境 GCP
(redash)server GKEのDeployment redash-server
(redash)scheduler
scheduled_worker
adhoc_worker
GKEのDeployment redash-worker
nginx GKEのDeployment redash-nginx
redis Memorystore for redis
postgres CloudSQL for PostgreSQL

上記表のように、redashのserverとworker群、そしてnginxはすべてGKEのDeploymentとして構成することにしました。redisとpostgresはGKEのDeploymentではなく、GCP上のそれぞれの専用サービスを利用する構成にしました。また、ローカル環境では不要でしたが、本番運用ではメール送信も必要になりますので、redashからのメール送信はSendGridを利用するようにしました。ここまでの構成を図でまとめますと、下記のような図になります。

f:id:allabout-techblog:20201015132406p:plain
Redash on GKEアーキテクチャ

上記図には記載していませんが、KubernetesのPodへのアクセスにはServiceが必要なので、svc-redash-nginxとsvc-redash-serverを構築しています。Serviceを構築している理由としては、podのIPはエフェメラルでpodを構築する度にIPが変わります。そのため、Serviceを構築することでIPが変わっても指定したpodにアクセスができるようになります。詳しくは公式サイトに説明があるので、ご参考ください。

nginxのカスタマイズ

docker-compose用のnginxは「redash/nginx:latest」イメージを使っていて、その中の設定ファイル(default.conf)は下記のようになっています。

変更前

upstream redash {
  server redash:5000;
}

server {
  listen   80 default;

  gzip on;
  gzip_types *;
  gzip_proxied any;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

    proxy_pass       http://redash;
  }
}

upstream項目で指定している「server redash:5000;」が、nginxサーバーへアクセスが発生したらredashサーバーの5000ポートへつないでくれる設定になります。GKE上でnginxを構成する際には、この値をredash-serverのServiceに変更する必要があります。また、後述しますが、ステージング環境と本番環境で同じnginxイメージを使う想定なので、default.confのserver値を変数化し、ステージング環境と本番環境のそれぞれのマニフェストから値を設定できるようにしました。カスタマイズした設定ファイルは下記のようになります。

変更後

upstream redash {
  server ${UPSTREAM_SERVER}:${UPSTREAM_PORT};
}

server {
  listen   80 default;

  gzip on;
  gzip_types *;
  gzip_proxied any;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

    proxy_pass       http://redash;
  }

} 

ちなみに、カスタマイズした設定ファイルは、変数の置換が必要になるためファイル名も「default.conf.template」にし、実際のデプロイの際に変数が置換された状態の「default.conf」ファイルを生成するようにしています。こちらの内容は後述するマニフェストにて紹介させていただきます。

このようにカスタマイズしたnginxイメージはGCR(Google Container Registry)のある場所へ格納することでマニフェストから参照できるようにしました。

マニフェスト

前述したとおり、GKEのDeploymentへのアクセスはServiceを利用します。そして、DeploymentもServiceもGKEのクラスタに属されています。今回のGKE構成を表で表すと下記のようになります。

GKE要素 サービス名
Cluster redash-cluster
Deployment redash-server
redash-worker
redash-nginx
Service svc-redash-server
svc-redash-nginx

redash-workerの場合、内部でceleryプロセスが動いていて、redisとPostgreSQLと経路を書く方できればredash-serverやそれ以外との経路は不要なので、専用のServiceを持つ必要がないです。従ってServiceは2つだけになります。また、redashで利用するためのMemorystore for redisとCloudSQL for PostgreSQLはそれぞれのサービスで新規作成するだけで簡単に構築できました。これらの構成を行うために5つのマニフェストファイルを作成したので、それぞれ記載させていただきます。 ※弊社ではCircleCIを使ってのデプロイを行っているため、マニフェストファイルの中にプロジェクト毎のCircleCI環境変数を使っています。

deployment-redash-server

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redash-server
  labels:
    app: redash-server
spec:
  selector:
    matchLabels:
      app: redash-server
  template:
    metadata:
      labels:
        app: redash-server
    spec:
      containers:
      - name: redash-server-container
        image: redash/redash:8.0.0.b32245
        command:
        - /bin/sh
        - -c
        - /app/bin/docker-entrypoint create_db; /app/bin/docker-entrypoint server
        resources:
          limits:
            memory: "1Gi"
          requests:
            memory: "512Mi"
        env:
          # redashで利用する環境変数
        - name: DB_USER
          value: ${DB_USER}
        - name: DB_PASS
          value: ${DB_PASS}
        - name: DB_NAME
          value: ${DB_NAME}
        - name: TZ
          value: "Asia/Tokyo"
        - name: PYTHONUNBUFFERED
          value: "0"
        - name: REDASH_LOG_LEVEL
          value: "INFO"
        - name: REDASH_WEB_WORKERS
          value: "4"
        - name: REDASH_REDIS_URL
          value: "redis://${REDIS_IP}:6379/0"
          # ここで設定した環境変数を利用するため{}ではなく()となる
        - name: REDASH_DATABASE_URL
          value: "postgresql://$(DB_USER):$(DB_PASS)@127.0.0.1/$(DB_NAME)"
        - name: REDASH_HOST
          value: "https://${REDASH_HOST}"
        - name: REDASH_MAIL_SERVER
          value: "${REDASH_MAIL_SERVER}"
        - name: REDASH_MAIL_PORT
          value: "${REDASH_MAIL_PORT}"
        - name: REDASH_MAIL_USERNAME
          value: "${REDASH_MAIL_USERNAME}"
        - name: REDASH_MAIL_PASSWORD
          value: "${REDASH_MAIL_PASSWORD}"
        - name: REDASH_MAIL_DEFAULT_SENDER
          value: "redash@example.com"
        ports:
          # このポート番号でsvc-redash-serverとつながる
        - containerPort: 5000
      # CloudSQL for PostgreSQLとつなげるためのcloud-sql-proxy設定
      - name: redash-cloud-sql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        command: ["/cloud_sql_proxy", "--dir=/cloudsql",
                  "-instances=${GCP_PROJECT_ID}:${CLOUDSQL_REGION}:db-${CLOUDSQL_INSTANCE}=tcp:5432"]
        volumeMounts:
        - name: ssl-certs
          mountPath: /etc/ssl/certs
      volumes:
      - name: ssl-certs
        hostPath:
          path: /etc/ssl/certs

deployment-redash-worker

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redash-worker
  labels:
    app: redash-worker
spec:
  selector:
    matchLabels:
      app: redash-worker
  template:
    metadata:
      labels:
        app: redash-worker
    spec:
      containers:
      - name: redash-worker-container
        image: redash/redash:8.0.0.b32245
        resources:
          limits:
            memory: "1Gi"
          requests:
            memory: "512Mi"
        env:
          # redashで利用する環境変数
        - name: DB_USER
          value: ${DB_USER}
        - name: DB_PASS
          value: ${DB_PASS}
        - name: DB_NAME
          value: ${DB_NAME}
        - name: TZ
          value: "Asia/Tokyo"
        - name: PYTHONUNBUFFERED
          value: "0"
        - name: REDASH_LOG_LEVEL
          value: "INFO"
        - name: REDASH_REDIS_URL
          value: "redis://${REDIS_IP}:6379/0"
          # ここで設定した環境変数を利用するため{}ではなく()となる
        - name: REDASH_DATABASE_URL
          value: "postgresql://$(DB_USER):$(DB_PASS)@127.0.0.1/$(DB_NAME)"
        - name: WORKERS_COUNT
          value: "2"
        - name: QUEUES
          value: "queries,scheduled_queries,celery"
        - name: REDASH_HOST
          value: "https://${REDASH_HOST}"
        - name: REDASH_MAIL_SERVER
          value: "${REDASH_MAIL_SERVER}"
        - name: REDASH_MAIL_PORT
          value: "${REDASH_MAIL_PORT}"
        - name: REDASH_MAIL_USERNAME
          value: "${REDASH_MAIL_USERNAME}"
        - name: REDASH_MAIL_PASSWORD
          value: "${REDASH_MAIL_PASSWORD}"
        - name: REDASH_MAIL_DEFAULT_SENDER
          value: "redash@example.com"
        args: ["scheduler"]
      # CloudSQL for PostgreSQLとつなげるためのcloud-sql-proxy設定
      - name: stg-dmg-redash-cloud-sql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        command: ["/cloud_sql_proxy", "--dir=/cloudsql",
                  "-instances=${GCP_PROJECT_ID}:${CLOUDSQL_REGION}:db-stg-${CLOUDSQL_INSTANCE}=tcp:5432"]
        volumeMounts:
        - name: ssl-certs
          mountPath: /etc/ssl/certs
      volumes:
      - name: ssl-certs
        hostPath:
          path: /etc/ssl/certs

deployment-redash-nginx

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redash-nginx
  labels:
    app: redash-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redash-nginx
  template:
    metadata:
      labels:
        app: redash-nginx
    spec:
      containers:
      - name: redash-nginx-container
        # カスタマイズ済みのnginxイメージを格納しているGCR情報
        image: ${GCR_PATH}/${IMAGE_NGINX_NAME}:${IMAGE_NGINX_TAG}
        resources:
          limits:
            memory: "256Mi"
          requests:
            memory: "256Mi"
        env:
          # nginx設定ファイルで利用する変数設定
        - name: UPSTREAM_SERVER
          value: "svc-${REDASH_SERVER}"
        - name: UPSTREAM_PORT
          value: "5000"
          # envsubstコマンドを使って変数を置換する
        command: ["/bin/sh", "-c", "envsubst '$$${ENV_UPSTREAM_SERVER}$$${ENV_UPSTREAM_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && /usr/sbin/nginx -g 'daemon off;'"]
        ports:
        - containerPort: 80

カスタマイズ済みのnginxイメージを利用していますが、設定ファイルで利用する変数設定でちょっと苦労したので少しだけ補足させていただきます。
default.conf.templateファイルでは${UPSTREAM_SERVER}と${UPSTREAM_PORT}を記載しており、envsubstコマンドを使って該当変数をマニフェストの値に置換し、その結果をdefault.confファイルへ書き出すのがゴールになります。普通のenvsubstコマンドで書くと下記のような感じになります。

envsubst '$$UPSTREAM_SERVER$$UPSTREAM_PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

※envsubstコマンドについては、Docker上のNginxのconfに環境変数(env)を渡すたったひとつの全く優れてない方法(修正:+優れている方法)を参照にしました。

envsubstコマンドも不慣れだったものの、マニフェストファイルで書いてkubectlコマンドで実行するだけならシンプルですが、CircleCI経由になると余計に変数設定-置換が怪しくなり、いくつかの試行錯誤でやっと上記マニフェストのような書き方にたどり着きました(後から見ると当たり前のように見えるものが、何かにはまっちゃうと見えなくなりますよね;;;)。ここで、恥ずかしながら試行錯誤の内容も書かせていただきます。

envsubst記載の試行錯誤

  • ゴール : envsubst '$$UPSTREAM_SERVER$$UPSTREAM_PORT'

  • kubectlコマンド用マニフェスト : envsubst '$$UPSTREAM_SERVER$$UPSTREAM_PORT'

  • CircleCI用マニフェストの試行錯誤
    ※Inputはマニフェストへの記載内容、OutputはCircleCIデプロイ時の置換後の内容になります。

Case# Input Output 備考
1 envsubst '$$UPSTREAM_SERVER$$UPSTREAM_PORT' envsubst '$$'
2 envsubst '${$UPSTREAM_SERVER}${$UPSTREAM_PORT}' envsubst '${}${}'
3 envsubst '$UPSTREAM_SERVER$UPSTREAM_PORT' envsubst ''
4 Input : envsubst '\$\$UPSTREAM_SERVER\$\$UPSTREAM_PORT' found unknown escape character
5 envsubst '$$$UPSTREAM_SERVER$$$UPSTREAM_PORT' envsubst '$$$$'
6 envsubst $$UPSTREAM_SERVER$$UPSTREAM_PORT envsubst $$
7 envsubst '$${ENV_UPSTREAM_SERVER}$${ENV_UPSTREAM_PORT} found unknown escape character CircleCIの環境変数利用
ENV_UPSTREAM_SERVER : \$UPSTREAM_SERVER
ENV_UPSTREAM_PORT : \$UPSTREAM_PORT
8 envsubst '$$${ENV_UPSTREAM_SERVER}$$${ENV_UPSTREAM_PORT} envsubst '$$UPSTREAM_SERVER$$UPSTREAM_PORT' CircleCIの環境変数利用
ENV_UPSTREAM_SERVER : UPSTREAM_SERVER
ENV_UPSTREAM_PORT : UPSTREAM_PORT

svc-redash-server

apiVersion: v1
kind: Service
metadata:
  name: svc-redash-server
  labels:
    app: svc-redash-server
spec:
  type: ClusterIP
  ports:
    - port: 5000
      targetPort: 5000
      protocol: TCP
  selector:
    app: redash-server

svc-redash-nginx

apiVersion: v1
kind: Service
metadata:
  name: svc-redash-nginx
  labels:
    app: svc-redash-nginx
spec:
  type: NodePort
  ports:
    - port: 80
      # このnodePort番号にてロードバランサとつながる
      nodePort: 30419
  selector:
    app: redash-nginx

kubectlコマンド

マニフェストも何回かの試行錯誤の結果、完成できました。試行錯誤の際に役に立ったいくつかのkubectlコマンドを簡単に紹介させていただきます。

podのリストを取得する

kubectl get pods

podの詳細情報を確認する

kubectl decribe pods POD-NAME

podのログを確認する

kubectl logs POD-NAME
kubectl logs POD-NAME -c CONTAINER-NAME # 1つのpodに複数のコンテナがある場合

deployment作成に失敗したり、エラーが発生したり等の場合には上記コマンドでどのような状況・エラーなのかの確認ができるので結構役に立ちました。

podに対してポートフォワードする

kubectl port-forward pod/POD_NAME LOCALHOSTのPORTNUMBER:PODのPORTNUMBER

上記コマンド実行後、ブラウザに「localhost:LOCALHOSTのPORTNUMBER」と書くと、ブラウザから該当podへアクセスすることが可能です。

Serviceに対してポートフォワードする

kubectl port-forward svc/SERVICE_NAME LOCALHOSTのPORTNUMBER:SERVICEのPORTNUMBER

podにブラウザからアクセスできることと同じく、Serviceにもブラウザからアクセスすることができます。これで、podへのアクセスに問題があるかどうか、Serviceへのアクセスに問題があるかどうかの確認ができるので便利ですねー

CircleCI設定

前述の通り、弊社ではCircleCIを使ってデプロイを行っています。今回作成したマニフェストを使ってデプロイするCiecleCI設定内容の一部を記載させていただきます。

version: 2.1

commands:
  
  deploy_to_kubernetes:
    steps:
      - run:
          name: Deploy to Kubernetes
          command: |
            envsubst < yaml_files/${YAML_FILES_DIRECTORY}/deployment-${ENVIRONMENT}-${REDASH_NGINX}.yaml > ./patched_deployment_nginx.yaml
            envsubst < yaml_files/${YAML_FILES_DIRECTORY}/deployment-${ENVIRONMENT}-${REDASH_SERVER}.yaml > ./patched_deployment_server.yaml
            envsubst < yaml_files/${YAML_FILES_DIRECTORY}/deployment-${ENVIRONMENT}-${REDASH_WORKER}.yaml > ./patched_deployment_worker.yaml
            envsubst < yaml_files/${YAML_FILES_DIRECTORY}/svc-${ENVIRONMENT}-${REDASH_NGINX}.yaml > ./patched_svc_nginx.yaml
            envsubst < yaml_files/${YAML_FILES_DIRECTORY}/svc-${ENVIRONMENT}-${REDASH_SERVER}.yaml > ./patched_svc_server.yaml
            kubectl apply -f ./patched_deployment_nginx.yaml
            kubectl apply -f ./patched_deployment_server.yaml
            kubectl apply -f ./patched_deployment_worker.yaml
            kubectl apply -f ./patched_svc_nginx.yaml
            kubectl apply -f ./patched_svc_server.yaml
            kubectl rollout status deployment ${ENVIRONMENT}-${REDASH_NGINX}
            kubectl rollout status deployment ${ENVIRONMENT}-${REDASH_SERVER}
            kubectl rollout status deployment ${ENVIRONMENT}-${REDASH_WORKER}

後はCircleCIを起動して無事デプロイできることも確認でき、実際にRedashも起動していることを確認できました。

おわりに

ここまでがGKE上にRedashを構築するためにやったことになります。インフラにはそこまで詳しくない自分がredashのアーキテクチャーを理解し、試行錯誤しながらマニフェストを作成してGKE構成までできたので、今回の経験を活かしていきたいと思います。
余談ですが、今回構築した環境でRedashのダッシュボードを作成し、要望があった部署へ提供することで実際に使ってもらっていて嬉しいですー
長文になりましたが少しでもGKEの構成を理解いただき、GKE上でRedashを構築してみようと思う方へ役に立てればと思います。

閲覧ありがとうございました!今後ともよろしくお願いいたします。