思ったより文章にしないなという話

コロナで外出が規制されて以来、もともとあまりあまり外に出ない/人に会わないでも支障がない(ように見える)ので、さらに人と会わなくなりました。

そこでやっぱり感じるのは、情報ってほとんど文章にならないんだなってことです。この情報を文章にしておいたり、ドキュメント化しておくということは思った以上に負荷の高いものみたいです。

これは多分、エンジニア をやられている方ならそりゃそうだろって話だと思うのですが、改めて普段の情報共有がいかに話すことによって行われていたのかを実感します。

Mediumとか読んでると英語圏の情報の質の高さにびっくりします。

インターネットが普及したことによって、より英語の存在感というか、英語を使えることでのメリットは日に日に増すばかりです。

とりあえず、前も書いた気がしますが、意識してちゃんと情報発信したいと思います。

Posted By :
Comment :0

ついに写真のローカル保存をやめて全てGoogleCloudPlatformのArchive class storageに上げた話

写真のデータは年々増えていきます。

増えていると言っても全体で3TBぐらいなのですが、これをどのように保管するかは結構悩ましい問題です。

プロの人、動画の人とかはいったいどうしてるやら。。。プロの人であるほど終わったやつは削除してしまうのかもしれません。

それは置いておいて、JPGならGooglePhotoがかなり高画質で無制限に保存してくれた上でいろいろな付加情報をつけてくれるのでベストだと思います。

ただ、RAWを保管したい、、、となると、一応AmazonPrimePhotoが保管できるようですが、あまりメジャーじゃないようです。
Amazonなので大丈夫だとは思いますが、今後このサービスがどうなるのかもちょっと心配でした。また、アップロードはGooglePhotoと同じでディレクトリ構造を維持できないため、ちょっとなーと思っていました。

そんな時、RAID5を構成していた4台のうち1台が壊れました。HDDが壊れるのは初めてでした。

ついにその時がきたか、、、ということで、もういっそのことクラウドにあげる事を決断しました。

以下結構ざっくり書いてるので、気軽にコメントで質問ください。

選定:AWSかGCPか

まず最初にAWSかGCPどちらにしようかなと考えました。(Azureは触ったことがないので外しました)

GCPの方はこんな感じ

https://cloud.google.com/storage/pricing?hl=ja

AWSはこんな感じ

https://aws.amazon.com/jp/about-aws/whats-new/2019/03/S3-glacier-deep-archive/#:~:text=S3%20Glacier%20Deep%20Archive%20%E3%81%AF,%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8%E3%82%92%E6%8F%90%E4%BE%9B%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

若干GCPの方が高いですが、10TBとか20TB程度では誤差です。

初めてこういったクラウドサービスの料金を見た方は安くてびっくりするかもしれませんが、勘違いしてはいけないのは、こういった長期保存用と銘打たれているストレージは取り出しにとてつもないコストがかかる場合があるという点を肝に銘じておく必要があります。(最近はマシになりました)

https://qiita.com/damacchi/items/797ef13fd88c49ba7bb7

https://qiita.com/daktu32/items/2dbab869dca6a3603e5d

https://digital-chiebukuro.com/aws/amazon-glacier-kaizen/

また、最低保管期間というものがあることも認識しておく必要があります。

AWSの場合

GCPは

この辺りの料金、、、かなり複雑なので多分この辺りで敬遠されて使わない方が多いのかなと思っています。

実際、正確にコスト感を把握するのは難しいです。一通り読んで出した結論は

結論: 取り出し料金がわかりやすかったGCPにした

AWSの方は取り出す時間に応じて料金が変わる仕組みになっています。実際業務の利用ではこちらの方が猛烈な量のビックデータをゆっくり取り出したり、一部を早く取り出したりとカスタマイズが効いて使いやすいはずです。

GCPの方はそういった概念がなく、すぐに出てきます。最低1、2時間かかるAWSに比べてGCPの方はブラウザで普通に閲覧できてしまいます。(謎技術)

その代わり料金は以下のような感じでお高めです。

そもそも多くて数十Tの話なので迷うような話でもないのですが、ユースケースとして一気に落としてきて検索するといった使い方よりもGooglePhotoの方で見てから欲しいRAWを数枚落とすという方が多いと考えたので、GCPの方にしました。

他にかかる費用

さて、主にかかる費用はこの保管費用と取り出し費用ですが、それ以外にも保存の時にかかる場合がある費用に触れます。

今回の場合以下表にある オペレーションコストというものがかかる可能性があります。

例えば、、、

保存してたら途中で止まっちゃったのでまだ保存してないやつだけ保存したい

みたいな事をすると、ローカルのデータとクラウドに保存されているデータが同じかどうかを確認する作業のためにこのオペレーションコストがかかったりします。

今回の場合写真データという事で、件数はそこまでいきません。最悪千円ぐらいかかっちゃうかもなぐらいの見積もりで進めました。

同期の方法

今回はWindowsの自作PCの中にあるHDD8台の中身保存しました。

まず最初にWindowsなので

https://cloud.google.com/storage/docs/gsutil_install?hl=ja

こちらからCloud SDKをインストールします。

同時に、Storageのコンソールからバケットを作成します。Shellからも作れますが、間違えると痛いので(削除に費用がかかる場合がある)コンソールからやっています。

インストールしたらSDK Shellを起動してコマンドでアップロードを開始します。今回はDドライブの内容全てをphoto01というバケットにアップロードしています。

gsutil -m cp -r D:¥ gs://photo01/

これでアップロードが開始されます。

-m というのは、同時に幾つかのデータを上げようとするというオプションなのですが、ご家庭の回線/HDDのアクセス速度によっては余計に遅くなってしまうかもしれません。一度試しに10枚ぐらいの写真をアップロードしてみて、速度を見ながらつけるかどうかを試してみてください。

Posted By :
Comment :0

ReactでFirebaseUIを日本語化

FirebaseUIを日本語で使いたい時、Reactでやってる例がなかったためメモ程度に書いておきます。質問あればコメントください。

結論: react-firebaseui-localizedを使う

1年前に公開されたものなので今後どうなるかわかりませんが、とりあえずこれで導入しました

https://github.com/greg-schrammel/react-firebaseui-localized#readme

サンプルコードそのままです。

import FirebaseUIAuth from "react-firebaseui-localized";

import firebase from "firebase/app";
import "firebase/auth";

const firebaseApp = firebase.initializeApp(/* your firebase keys */);

const config = {
  signInFlow: "popup",
  signInSuccessUrl: "/home",
  signInOptions: [
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.FacebookAuthProvider.PROVIDER_ID
  ],
  tosUrl: "/terms-of-service",
  privacyPolicyUrl: "/privacy-policy"
};

function Login() {
  return (
    <FirebaseUIAuth
      lang="ja"   //ここを'ja'にするだけ
      config={config}
      auth={firebaseApp.auth()}
      firebase={firebase}
    />
  );
}

これだけで日本語化できます。


エラーメッセージもちゃんと日本語化されてました

Posted By :
Comment :0

iPhoneからMacのIPにアクセスした時Fireauthでログインできるようにする

FireAuthを使って開発をしていて、いざCSSの調整に入ろうとしてiPhoneからMacのIP:3000にアクセスすると、Authでログインするために承認済みドメインに追加してくれと言われる。

いままで全く意識してなかったけれども、FirebaseAuthの管理画面にいくとちゃんとlocalhostとFirebaseHostingで使われているドメインが追加されていた。

なのでそこに現在のMacのIPアドレスを追加すると、ちゃんとログインできるようになる。

Posted By :
Comment :0

突然Lightsailでホスティングしてるこのブログがデータベース接続の確立エラーで開けなくなった(解決)

突如このブログがよく起こるデータベース接続の確率エラーで開けなくなっていました。

様々なブログを見て解決しようとするも解決しなかったため、仕方なくSSH接続してみましたが、特にwp-config.phpが書き換わってる様子もありませんでした。

結論 : SSDの容量不足

結論としてはSSDの容量がいっぱいになってしまっていたことが原因でした

lightsailのコンソールからSSH接続して df -h してみると

これはもう40GBに増やした後のものですが、20GBの方がほとんどだと思います。usageが100%になっていました。

もしlightsailで突然データベース接続エラーが出た方は、一度疑ってみてください。

次またいっぱいになった時には、画像ファイルをS3に移したりするかもしれません。

Posted By :
Comment :0

React Tutorialを初めてやったとき勘違いしてたことメモ

なんで上書きされないの?

 render() {
        const status = 'Next player: X';

        return (
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}//なんで一つ前の0を上書きしない??
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }

→関数を呼んでいるから、上書きするわけではなく1を入れたときの結果が入るという話。

なんで多次元配列になってる?(なってない)

[
  'O', null, 'X',
  'X', 'X', 'O',
  'O', null, null,
]
//急にどうして多次元配列にできてるの?

なってない。多次元配列だとすると以下のようになる

[
  ['O', null, 'X'],
  ['X', 'X', 'O'],
  ['O', null, null]
]

なんでrender()内で定義するの?

  render() {
    const history = this.state.history; //render()の上でも良くない?
    const current = history[history.length - 1];
    const winner = calculateWinner(current.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div className="game">
        <div className="game-board">
          <Board
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }

Classの中はメゾットしか書けないとのことでした。

これなに?(三項演算子)

    const moves = history.map((step, move) => {
      const desc = move ?    // ? ???
        'Go to move #' + move : // : ???
        'Go to game start';
      return (
        <li>
          <button onClick={() => this.jumpTo(move)}>{desc}</button>
        </li>
      );
    });

条件式 ? Trueの処理 : Falseの処理

https://www.sejuku.net/blog/23627

実行結果を見ると分かりますが、JavaScriptでは「null」「undefined」を条件式に当てはめるといずれも「False」と判断されてしまいます。

https://www.sejuku.net/blog/23627

つまり、history,最初の時にはnullでfalseとなるのでGo to game startとなるということでした。

Posted By :
Comment :0