新着記事

Viewing posts from December, 2019

TORICO全社会イベント TORICO NIGHT 2019 でオペレータしました

Qiita の TORICO Advent Calendar 2019 の記事として書きました

TORICO NIGHT

TORICOでは、年2回のペースで全社員任意参加の食事会「TORICO NIGHT」を開催しています。

2017年から開始して、201911月の開催で5回を迎えました。

多くの会社は、12月に「忘年会」という形で食事会をされると思いますが、TORICO12月は商品が非常に多く売れる時期であり、物流チームも事務チームも気が抜けなくなるため、その時期を避けて秋口に食事会をします。

開催場所

TORICOでは、マンガの原画展やトークイベントを行うためのイベントスペースを自社運営しています。TORICO NIGHT を開催する際も自社イベントスペースを使うことが多くあります。

今回の TORICO NIGHT は、自社運営の池袋のイベントスペース「池袋虜」で行うこととしました。

運営スタッフ

TORICO NIGHT の運営スタッフ(幹事)は、毎回くじ引きなどで決めます。イベントの最後に、当会の幹事が決めた方法で次回幹事を決めることが多いです。2019年春のTORICO NIGHT での決め方は「役員によるくじ引き」で、私は自分自身を引き当ててしまったため2019 TORICO NIGHT の幹事となりました。

2019年秋の幹事は、部門がそれぞれ違う5名が選ばれました。その5名で、次のTORICO NIGHT の全てを決め、実施することになります。

実施6週間前

顔合わせ、役割分担決め

実施時期が近づいたので、幹事チームで集まっておおよその役割を決めます。

私は、製作物のデザインや製作、本番のPA、照明のオペレーションを担当することにしました。

その他のメンバーで、ケータリングの手配や参加者への案内、会場押さえなどをします。当日の進行は全員で作ります。

今後、週イチで一時間ほど使って幹事チームで集まることを合意し、Slackのプライベートチャンネルを作ってミーティングは終了しました。

実施5週間前

テーマ決め、ケータリング決め

会のテーマやおおよその進行を決めます。ケータリングは早めに業者を決めて、予約を取ります。

予算としては単価3000円強、ドリンク別 程度からあります。前回のケータリングの感想をメンバーで話し合いながら、良さそうな所を選定します。

今回の会のテーマとして、クイズ主体で行ってみようと決めたので、問題の提出を宿題としてMTGは終了しました。

実施4週間前

進行の詰め

全体のタイムテーブルを詰めます。

クイズ以外のゲームのテストプレイをしながら、全体の時間規模を見積もります。

この段階で必要な製作物が見えてきますし、会場設営の図面も見えてきます。

実施3週間前

必要なものの洗い出し。当日の司会進行の確認など。

私は音響と照明を担当するため、現地会場を観察しながら、機材設備の数や状態を確認します。

今回はクイズのコンテンツとして、社外の脱出イベントで見るような謎解きゲームを少し盛り込みたいと思っていたので、会場を観察してその題材も探します。

会場である池袋虜は、TORICOが運営する前はクラブとして使われていました。ワンマンオペレーションか出来るよう、ステージ上のDJ卓のまわりにPA・照明設備が配置されています。

池袋虜の図面

この形だと外音を作るのも大変ですし、画面や照明を見ながらのオペレーションができませんので、なんとか配置を直したいところです。

マルチケーブルを会場奥まで取り回して、メイン卓を移動させるのも考えましたか、1日の社内イベントのためだけにやるのは手間がかかりすぎるので低優先とし、他の方法を探します。

池袋虜のPA卓「PRESONUS StudioLive 16.0.2 USB」は、USBで接続したPCでリモートコントロールができます。調光卓も、すでにWindows PC の Surfaceでコントロールできるようになっています。そのため、15mUSBケーブルで、コントロール用のPCだけ客席に配置する方法で行くことにしました。

当日は客席の隅に私のオペレーションブースを作り、PC4台で演出をコントロールすることにします。4台の役割としては

Mac1 スライド (keynote)
Mac2 BGM (iTunes, vlc)
Mac3 PAミキサー
Win1 調光卓

となります。

1PCに複数のアプリを使って台数を減らせますが、オペレーターである私が混乱してミスをする可能性もあるため、1PCに1つのアプリでわかりやすくします。

ディスプレイは、今回は全部で3台使いました。HDMI分配器を使って全てのディスプレイに同じものを映します。

実施2週間前

クイズ問題の調整と確定

配点の計算、想定できるエラーのシミュレーション、集計と伝達方法など詰めます。

デザインクリエイティブもほぼ出来上がっているので、試し刷りをして使用感を確認します。

制作物

作ったものとしては、

  • ネームカード用紙
  • 謎解き用問題用紙
  • ドリンクメニュー
  • 会場地図
  • くじ引き用ネームカード

などを作りました。

ネームカード用紙

名刺カードにプリントしたのですが、フチなしプリントはA4に8面配置のクリアカット用紙がきれいに印刷できて使いやすく、よかったです。

四隅に色がついているのは、謎解きゲームで使うためです。

くじ引き用ネームカード

次回幹事決めのためのくじを作ります。これも名刺カードで作りました。くじ引きは電子化(アプリ化)もできますが、アプリにすると運営が操作しているように見える可能性もあるため、印刷物で作ります。

コストと使いやすさ、当選発表の時の見た目のバランスを考えて、名刺カードで刷ることにしました。自動印刷をしやすくするため、A4面付けの用紙ではなく既に名刺サイズになっている用紙を使います。

HTML + jQuery でページを作って印刷しました。

Github

HTML

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="business-card.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"
            integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
            crossorigin="anonymous"></script>
</head>
<body>
<script>
const nameSource = `
漫画 全館子
スキマ ネ子
ホーリン ラブ子
まんが 王子
マンガ テンコ
`;
    const names = nameSource.split('\n').filter(i => i);
    $(function () {
        const $body = $('body');
        for (const name of names ){
            const $card = $('<section>').addClass('sheet');
            const $name = $('<div>').addClass('name');
            $name.text(name);
            const $signature = $('<div>').addClass('signature');
            $signature.text('TORICO NIGHT 2019.11');
            $card.append($name);
            $card.append($signature);
            $body.append($card);
        }
    });
</script>
</body>
</html>

SCSS

* {
  box-sizingborder-box;
}
htmlbody {
  margin0;
  padding0;
}
@page {
  size91mm 54.5mm;
  margin0;
}
@media print {
  body {
    width91mm/* needed for Chrome */
  }
}
.sheet {
  width91mm;
  height54.5mm/* 0.5mm余裕をもたせる */
  // page-break-after: always;
  page-break-beforealways;
  positionrelative;
  margin0;
  padding5mm;
  &:nth-of-type(1) {
    page-break-beforeauto;
  }
  .name {
    width100%;
    margin-top15mm;
    height10mm;
    line-height10mm;
    //border: 1px solid black;
    font-size13mm;
    text-aligncenter;
  }
  .signature {
    width100%;
    margin-top10mm;
    height10mm;
    line-height10mm;
    font-size3mm;
    color#777;
    text-aligncenter;
  }
}
/* プレビュー用のスタイル */
@media screen {
  body {
    background#eee;
  }
  .sheet {
    backgroundwhite/* 背景を白く */
    box-shadow0 .5mm 2mm rgba(000.3); /* ドロップシャドウ */
    margin5mm;
  }
}

ドリンクメニュー

てきとうに時間をかけずにささっと。

(ダサい枠線の黒丸はクイズ中の謎と関連させるためです)

実施1週間前

準備は終わっているため、大きな作業は特にありませんでした。
当日の進行やクイズ問題の出題方法の確認を行います。

また、購入物が揃っているかの確認も行っておきます。

ちなみに、Keynote のスライドは、150枚ほどになりました。スライドをしっかり組むほど、当日はリラックスしてオペレーションできます。

当日

準備通りにイベントを進行します。小さなトラブルはいくつかありましたが、リカバリしつつ無事にイベントを終えることができました。

次回運営担当者に向けて

仕事のついでに行うものなので、できる範囲で、リラックスして設計してください。ただし、自社運営会場を使う場合、ケータリングやドリンクの提供方法は、早めに決めたほうが良いでしょう。

スライドを使うのであれば、やっぱり Keynote が使いやすく美しいと思います。

一生懸命がんばっても、参加者に冷たい態度を取られることはあるかもしれません。そういった方を見つけてしまっても、心を動かされずに練習どおり最後まで通し切るのが良いでしょう。それが、他の楽しんでいる方のためになります。

旧Redash(V2) から 新Redash(V8) にアップデートを行いました

Qiita の TORICO Advent Calendar 2019 の記事として書きました

社内での実績閲覧のツールとして Re:dash を使っています。

最初に導入した Re:dash v2 のまましばらくアップデートを行っていなかったので、v8 にアップデートを行いました。

アップデート方針

v8 は dockerコンテナで提供され、 docker-compose で起動させることができます。提供されている docker-compose.yml は、Postgres や redis コンテナの起動も自動でされますし、インストールスクリプトも良くできており、初期状態の ubuntu サーバであればコマンド一発で docker エンジンのインストールも含めアプリの起動まで行うことができます。

従来の EC2イメージの Redash から、スクリプトでアップデートできたら楽なのですが、少し試したところ Postgres の DB のスキーマ名が変わっていたり、Postgresのサーバのバージョンも 9.3 -> 9.6 への大きなアップデートとなることもあり、今回は「Redash v8 を新規EC2で起動し、旧サーバからDBのレコードをコピーする」という方針としました。

Redash V8 サーバの構築

https://github.com/getredash/setup/ こちらのスクリプトを使うことで、非常に簡単に起動させることができます。

1. EC2 で Ubuntu18 サーバを起動

2. ホームディレクトリで、

git clone git@github.com:getredash/setup.git

3.

cd setup
bash setup.sh

あとは、スクリプトの中で docker エンジンのインストール、postgres のデータファイル構築や ランダムなDBパスワードの作成、初期スキーマの構築などすべて行ってくれます。スクリプト終了時に docker-compose up -d まで行うため、ブラウザでアクセスすれば Redash のサインインページが表示されます。

postgres コンテナへの接続

インポートするために、Postgres の Docker コンテナに外部から接続できるようにします。

上記スクリプトで Redash をインストールした場合、/opt/redash/docker-compose.yml が作成されますので、この postgres サービスの箇所に

 postgres:
image: postgres:9.6-alpine
env_file: /opt/redash/env
volumes:
- /opt/redash/postgres-data:/var/lib/postgresql/data
restart: always
# 追加
ports:
- "5432:5432"

ports項目を追加し、ホストマシンの5432ポートをコンテナに接続します。
/opt/redash/env の POSTGRES_PASSWORD に作成されているパスワードと、ユーザー名 postgres でコンテナの postgres に接続できます。

旧サーバの暗号キー等の設定のコピー

旧サーバの、/opt/redash/.env の設定値を新サーバにコピーします。

REDASH_COOKIE_SECRET 

REDASH_COOKIE_SECRET は、DBの data_sources テーブルにある暗号化フィールドの復号化に使われますので、テーブル内容をそのままコピーする場合は一致させる必要があります。

これを一致させない場合、Redash 起動時の data source の選択の際にローディングスピナーがぐるぐる回り続けることになります。APIレスポンス自体はHTTP500が返ってきており、docker-compose のログには Pythonの例外が、暗号化内容を復号できない旨のメッセージと共に出力されます。肝心のトレースバック(スタックトレース)は保存し忘れました。

実際のDBの復号化には settings.DATASOURCE_SECRET_KEY が暗号キーとして使われ、settingsを読んでみると

COOKIE_SECRET = os.environ.get("REDASH_COOKIE_SECRET", "c292a0a3aa32397cdb050e233733900f")
SECRET_KEY = os.environ.get('REDASH_SECRET_KEY', COOKIE_SECRET)
DATASOURCE_SECRET_KEY = os.environ.get('REDASH_SECRET_KEY', SECRET_KEY)

このようになっており、DBの暗号キーとクッキーの暗号キーは個別に設定できるようですが、旧Redashの場合はそれぞれ同じ値を使っていると思いますので、新サーバの /opt/redash/env には 旧サーバの /opt/redash/.env から REDASH_COOKIE_SECRET の内容だけコピーしておきます。REDASH_SECRET_KEY ができていたら項目ごと消しておきます。

その他の設定

Google (Gsuite ) を使っている場合は、

REDASH_GOOGLE_APPS_DOMAIN
REDASH_GOOGLE_CLIENT_ID
REDASH_GOOGLE_CLIENT_SECRET

をコピーすることで新サーバでもGoogle 認証が行えるようになります。そのほか、REDASH_MAIL_* など、旧サーバの設定内容はそのままコピーします。

REDASH_GOOGLE_CLIENT_ID="1xxxxxxxx.apps.googleusercontent.com"

このように、ダブルクォーテーションで囲っているとV8ではうまく動作しませんので、envファイル内でダブルクオーテーションは書かないようにします。

テーブル内容のコピー

おそらく、慣れてる方であれば pg_dump を使うのが良いと思うのですが、私は postgres や pg_dump の経験があまり無いため、datagrip を使ってSELECT 結果から INSERT 文を生成し、それをコピペで流し込むことにしました。

旧Redash からの変更点として、データベーススキーマ名が redash から postgres に変更されたこと、また旧版の queries テーブルや dashboards にあった user_email フィールドが無くなっていることなどあり、pg_dump での対応が難しそうだと思ったためです。

データ量として 700クエリー、30ダッシュボード、60ユーザー程度の規模ですので、コピペで十分対応できました。なお、query_results テーブルに過去のSQL結果が入ってますが、2GB程度のストレージを使っており、不要だと思ったため今回は query_results は移行しませんでした。

旧サーバの postgres に接続し、以下のテーブル内容をコピーしていきます。

organizations
users
data_sources
groups
data_source_groups
queries
visualizations
dashboards
widgets

外部キー制約があるため、流し込む順番が違うと失敗しますが、上記の順番で INSERT できると思います。

queries , dashboards には user_email という不要フィールドがあり、queries にはさらに query_results への参照があるのですが、それらは不要なため下記のようなSELECT 文で datagrip 上で検索し、INSERT 文としてコピーして 新DBに INSERT します。

SELECT id, updated_at, created_at, org_id, data_source_id, name, description, query, query_hash, api_key, user_id, last_modified_by_id, is_archived, options, version, is_draft, schedule_failures, search_vector, tags, schedule
FROM public.queries
ORDER BY id;
SELECT id, updated_at, created_at, org_id, slug, name, user_id, layout, dashboard_filters_enabled, is_archived, version, is_draft, tags
FROM public.dashboards
ORDER BY id;

ついでに、MySQL データソースは RDS用のものが新たに出来ていたため、 data_sources の type フィールドは mysql から rds_mysql 変更しました。

シーケンスの更新

INSERT しただけではオートインクリメントPKに使われるシーケンス番号が1から始まり、新しいクエリを保存する時エラーになってしまうので、シーケンスも更新しておきます。

SELECT * FROM users_id_seq;
SELECT MAX(id) + 1 FROM users;
ALTER SEQUENCE users_id_seq RESTART WITH 61;

SELECT * FROM groups_id_seq;
SELECT MAX(id) + 1 FROM groups;
ALTER SEQUENCE groups_id_seq RESTART WITH 6;

SELECT * FROM data_sources_id_seq;
SELECT MAX(id) + 1 FROM data_sources;
ALTER SEQUENCE data_sources_id_seq RESTART WITH 24;

SELECT * FROM data_source_groups_id_seq;
SELECT MAX(id) + 1 FROM data_source_groups;
ALTER SEQUENCE data_source_groups_id_seq RESTART WITH 22;

SELECT * FROM dashboards_id_seq;
SELECT MAX(id) + 1 FROM dashboards;
ALTER SEQUENCE dashboards_id_seq RESTART WITH 37;

SELECT * FROM queries_id_seq;
SELECT MAX(id) + 1 FROM queries;
ALTER SEQUENCE queries_id_seq RESTART WITH 699;

SELECT * FROM visualizations_id_seq;
SELECT MAX(id) + 1 FROM visualizations;
ALTER SEQUENCE visualizations_id_seq RESTART WITH 1230;

SELECT * FROM widgets_id_seq;
SELECT MAX(id) + 1 FROM widgets;
ALTER SEQUENCE widgets_id_seq RESTART WITH 695;

このように、MAX(id) の結果をコピペしてALTER SEQUENCE していきました。1行で書けそうなのですが、経験が無く書き方がわからなかったため、愚直に書いてます。

これで、新サーバで旧サーバの状態が再現されていると思います。

nginx に SSL証明書を組み込む

自己認証局のSSL証明書がありますので、使います。

参考: dockerでredashのnginxをssl化したら思いの外ハマった

mkdir -p /home/ubuntu/nginx/certs

certs に、証明書 ( my-awesome.crt, my-awesome.key )を入れる 

/home/ubuntu/nginx/default.conf を作成

upstream redash {
server redash:5000;
}

server {
listen 80 default;
return 301 https://$host$request_uri;
}

server {
listen 443;
ssl on;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2;
ssl_ciphers "ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!EXPORT:!DES:!3DES:!MD5:!DSS";

gzip on;
gzip_types *;
gzip_proxied any;

ssl_certificate /etc/nginx/certs/my-awesome.crt;
ssl_certificate_key /etc/nginx/certs/my-awesome.key;

error_log /var/log/nginx/nginx_error.log;
access_log /var/log/nginx/nginx_access.log;

location / {
proxy_ssl_server_name on;
proxy_set_header Host $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;
}
}

/opt/redash/docker-compose.yml を修正

 nginx:
image: redash/nginx:latest
ports:
- "80:80"
- "443:443"
depends_on:
- server
links:
- server:redash
restart: always
volumes:
- /home/ubuntu/nginx/default.conf:/etc/nginx/conf.d/default.conf
- /home/ubuntu/nginx/certs:/etc/nginx/certs

最後に

繰り返しとなりますが、データソース選択ビューで、INSERTしたはずのデータソースが表示されず、ぐるぐるとローディングスピナーが回り続ける場合、旧サーバと settings.DATASOURCE_SECRET_KEY が一致していません。/opt/redash/env の REDASH_COOKIE_SECRET を旧サーバと同じにして、REDASH_SECRET_KEY 設定を消すとデータソースが見れるようになると思います。

Search