yikegaya’s blog

yikegayaのブログ

Rails+Postgresql環境でauto incrementなカラムを作る

RailsPostgresql環境で主キーではないauto increment(Postgresqlではsequenceというらしい)な属性をもつカラムを作る必要があってやり方迷った。で、結局こうした。

Migration内でで使えそうなRailsAPIが見つからなかったので(こんなことそんなにやる場面なさそうだし)executeで直接実行してしまった。

sequenceをcreate→テーブルをcreate→sequenceをテーブルに付与という処理が必要っぽい。

今年度入ってからしばらくPostgresqlだけどその前はMySQL、その前はOracleだったんでなんか毎回軽く戸惑うな。

class Add{カラム名}To{テーブル名} < ActiveRecord::Migration
  def up
    add_column :{テーブル名}, :{カラム名}, :integer, comment: "hogehoge"
    execute <<-ENDE
      create sequence {テーブル名}_{カラム名}_seq;
      alter table {テーブル名} alter {カラム名} set default nextval('{テーブル名}_{カラム名}_seq');
      alter sequence {テーブル名}_{カラム名}_seq owned by {テーブル名}.{カラム名};
    ENDE
  end

  def down
    remove_column :{テーブル名}, :{カラム名}, :integer, comment: "hogehoge"
  end
end

wheneverからsidekiq実行

Railsアプリでwhenever(cron使って良い感じにバッチのスケジューリングをしてくれるgem)からsidekiq(redisを使った非同期処理を提供してくれるgem)のワーカー実行したかったんだけど単純に{ワーカークラス}.perform_syncをschedule.rbからなぜか実行できなかったんでsidekiq-cliから実行してみた。その時のメモ

app/workers/sample.rb

class SampleWorker
  include Sidekiq::Worker

  def perform
    console.log("!!!!!test!!!!")
  end
end

config/schedule.rb

every 1.minutes do
  command "cd /app/rails/; /usr/local/bundle/bin/sidekiq-client push PatientImageWorker"
end

なぜかプロジェクトのルートにcdしてさらにsidekiq-clientをフルパスで指定しないと動かない(どっちか片方抜けると動かず)

S3に保存した画像のサービス内での扱い

S3に保存した画像画像にいろいろ情報つけて扱う実装で考えたこと。

例えばこの画像はプロフィール画像用でこれはメモ用、とかの属性つける場合どうしたら良いんだろ。RailsとReactで作ったWebサービスで使う想定。

S3の仕組みでオブジェクトにjsonメタデータ付与できるのでそれ使って実装しようとしたんだけどいまいち綺麗に実装できなそうだったんで、RDBでS3オブジェクトのURLと属性のカラム持つテーブル作って扱ったら割と楽に作れた。

DBにobject_urlと属性を保持するフラグとかステータスのカラム持たせて、APIでDBの値取り出してReactのstateに設定して作ってみた。 テーブル作らずにS3内で完結させることもできそうだけど、まあ、コストとかパフォーマンスとかの問題もないしメンテしやすいし扱いやすいし良いか

interface Image {
  object_url: string;
  avator_flg: boolean;
}

const [images, setImages] = useState([]);

const sampleMethod = (image_id) => {
  該当の画像に対する何かの処理
}

return(
    <>
  {images.map((image, i) => (
          <img src={image.s3_object_public_url} key={i}>
          <a onClick={sampleMethod(i)}>画像に何かの情報をつけたい</a>
  ))}
    </>
)

Reactで動画をキャプチャしてDBに保存する

Reactでビデオ要素をキャプチャしてDBに保存する実装のメモ。

サーバサイドは/api/internal/register_imageのエンドポイントを作ってbinary型のカラムに保存できるようにしておく

フロント側の実装

video要素をcanvasに描画してそのままrequestで送れる。

const sample = () => {
  const videoCapture = () => {
    const canvas = document.getElementById('video-canvas');
    const videoHeight = video.videoHeight;
    const videoWidth = video.videoWidth;

    canvas.height = videoHeight;
    canvas.width = videoWidth;
    canvas.getContext('2d').drawImage(video, 0, 0);
    const canvas_image = canvas.toDataURL('image/png');
    axios.post(
      '/api/internal/register_image',{
        headers: {
          'content-type': 'multipart/form-data',
        },
        image: image,
      }
    );
  }
  
  return (
    <video></video>
    <canvas id='video-canvas' hidden><canvus>
    <button onClick={videoCapture}>キャプチャする</button>
  )
}

こんな形式の値がpostされる。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4Xuy9iZOt2VXdue98c8431CghkISMaSOMsY3H6Gg3NgaDcdvR0dER/RfbbcAYDBJSSfVevfll5svxzkPHb6297/0y65WqJAGtwmRFxsvKvPe733DOPuusvfbarfVqvY4vy1frzom+7cz5XTsi+JfXL6/i5vpVrJfnsV5No9XqRKvVisVyEa31Mq7O38T5yat49eyTePH0SQx7/Viv1/o7t6a1jlivV7FuraPX68VyuY7Vahk345sYjUbx7W//evzSL/+92Dk4jGjxgatoxSrWsdTP88U8FouF3sNXuxXR7XRivV7qPFarVbQ7bb231WpHSycdsVwto91uR7fbjU6np4vi7+v1IpbLeazWK72OY7U7Hf3Mefa6Pf3/StdfN4x/W9FucWP8tVrx+rWucbla6WfOh+9O18fk53Z+87Pf6JvO6/Uv3/xtnX9vrfWeTqcfwed1u9Fqc34+B73B7/Lx9E/+nmPynnY7gnuiB9mN1bqle1H/vx0F9T7+lsfP+6fjbL5aES3OIY+xrmO1dWzOvd1uNc9K1/5X/eVPqHuSn8aAa37Vff2rPpmf9vh12s0hd+s6bj+OT39cjQn+Ze7No617sY5VLGOxmsR8NY3ZfByL1SouLm/i//2vfxh/9Ad/HOPRNF6/fh3X1zcxmy2i3xtqXjFX+4Od2N8/1Lwfj2exWC41hJlL3U4vOp1uaNi1WrFcLmI+X8R0Oo35jHm7jm6rp/fyNZlMNHF2d3b1+n6fWBGxXK70nn5/EMvFMqbTmeZ9p9PRXGIuL+dzz3WN44jVgniw1rjr9brRbncUI3gNX/y+xXfOSeZoxZLlchmz2Uyftbe/p/csFkvNOz6Lr8FgoDlMHOt2iR+cJ8ePmM6mGnbElna7q3lR94HX9bpdvZ/jdns9xRXu12q50n2ZjCdxfn6+iRnEnOFgGMP+IHaGg+j2OjFfTmK1WsRitojDw8P4lV/9+/Huu+/G48eP4+TkJK6urmI0HuserloR07mfjeJUuxPtbkd/6/X7Opf9g8PY29+Pfq+va1EsXiz0LPg7r+VrOh7HarXWuXLPBsMd/b2nmLuKyWQco9GNrmExn8V0NtbvHPPnEe0lISu67XX0OxE7g07s9tv
  • 表示側 サーバ側から上記の形式でデータを受け取ってそのままimgタグのsrcに指定して表示できる
  const [images, setImages] = useState([]);

  useEffect(() => {
    async function fetchImages() {
      const images = await axios.get
        '/api/internal/images'
      );
      setImages(images.data);
    }
    fetchImages();
  }, []);

  return (
    images.map((image, i) => (
      <img src={image.image} key={i}</img>
    )
  )

追記

DBに入れるとストレージ食うのでS3とかに入れた方がよかった。

作業効率を高めるために役立つこと

作業効率を上げるためにやってることメモ 

  • 環境変数に開発中のプロジェクトのパスを設定してすぐcdできるようにする
  • bashrcにgitのaliasを設定
  • bundle execとかよく使うコマンドもaliasにする
  • 設定ファイルをgithubで管理する(dotfile)
  • historyコマンドの上限を引き上げる
  • ターミナルにgitのステータスや言語のバージョンなどの情報を出す(starshipを使うといい感じになる)
  • マメにtodoリストを使う
  • macにAlfredを入れる
  • メモをクラウド管理する
  • chrome拡張、VScodeの拡張ツールで便利なものを地道に入れていく。
  • MAC、ブラウザ、ターミナル、エディタのショートカットを覚える

LPICの201試験受けてきた(合格)

LPICの201試験受けてきた。で、合格できた。

LPICレベル1の更新期限前にレベル2取得するか迷ってたけど、業務でインフラの知識もう少し欲しいな。。と思う場面が最近ちょくちょくあってせっかくなんで勉強してみた。

201試験の内容

参考書の目次より

こうして見てみると当面の業務はEC2なりFagate上のdockerコンテナの上で動くWebサービス開発になりそうなんでしばらくは使わない知識のが多いな。。

感想

リソース測定コマンドの使い方(top、htop、vmstat、iostat、iotop、sar、sadf、uptime、wなど)はすぐ役に立ちそう。この辺りややこしくていつどのコマンドを打てばいいかとか結果の見方も曖昧だったのである程度自信を持って使えるようになったのは嬉しい。

後はネットワーク周りの知識もトラブルの時に役に立つかな。

ただハードウェア調達してサーバ構築するような業務は当面なさそうだしカーネルやシステム起動の知識はクラウドベンダー側で解決されるはずなので、まあ当面は使わなそう。

まあ、OSの仕組み学べてなんとなく満足感あるしいいか。。

次は202試験受験予定でこっちの方がWebサーバ(Nginx、Apacheの扱い)やらDNSやらWeb開発に役に立ちそうな知識学べそう。だけど更新期限まではまだ時間あるしなんか気が済んでしまったので一旦他のことやるかな。

kubenetes触ってみた(Mac上で動くとこまで)

kubenetes調べて軽く動かしてみたのでメモ。

  • Dockerfile、docker-composeは作れる

くらいのところから

  • kubenetesの基本的なリソースは理解
  • ローカル環境でWebサービス動かせる

というくらいまでは到達できたと思われ。

そもそもkubenetesはなんなのか

とりあえずWebアプリとかの開発環境をDockerで作ろうとするとdocker-composeで作るのが主流だが、本番環境の運用にdocker-composeをそのまま持ってこうとすると以下の理由で厳しい

  • docker-composeは単一のホストで動かす用なのでアプリとDBなどのミドルウェアが同じホストで動いてしまう
  • docker-composeはスケーリングとかロードバランスとかロギングなど本番環境運用に十分な仕組みがない

なので上記の問題を解決するためにswarmとかAWSのECSとかDockerを本番環境で運用するためのツールがいくつか存在するが、その中で現状一番人気があって将来性もありそうなのがkubenetesらしい。人気で需要が増えているけど学習コストが高い、難しいってのもよく聞く。

教材

まずチュートリアルやってみた。これはブラウザ上のエミュレータみたいなので全部動かせるし手軽なのはよかったんだけど、まだ物足りない感じはあったので本棚からDocker/Kubenetesの本出してkubenetesのくだりだけ読んでみた。

ただ手を動かすには個人的にオンライン講座の方が快適なのでUdemyも受講してみた。この中だとUdemyが一番おすすめな感じ。

kubenetesのリソース

kubenetesにはリソースっていうkubenetesのオブジェクトの単位?というか部品?みたいなものがあってこれを1つ1つコマンドかymlファイルから作成して環境を作っていく。このリソースの理解がkubenetesの基本的なところっぽい。

以下基本的なリソースのメモ

リソース 説明
Node ホストのサーバ
Pod コンテナの最小単位
ReplicaSet コンテナの集合体、Podのラッパー
Deployment ReplicaSetの世代管理。Blue/Greenデプロイ的なことができる。RelicaSetのラッパー
Service Podはそのままだとクラスタ外からアクセスできない。このServiceをpodに当てるとアクセスできる
Ingree Serviceはレイヤー4での公開なのでURLのパスで振り分けたりできない。のでServiceに対してさらにL7のIngressの設定が必要
ConfigMap 環境変数をPodに渡す
Secret ConfigMapみたいなものだけどBASE64エンコードされる。BASE64エンコードは暗号化ではないのでこれだけだと安全ではない
PersistentVolume Podが使うストレージのサイズや種別の定義
PersistenVolumeClaim 名前の通りPersistentVolumeを要求(Claim)し動的に確保するための仕組み

他にもいろいろあるっぽいけど基本はこの辺り。Node以外はdocker-composeと同じようにymlかjson(ymlが推奨)でインフラのコード化ができる。で、そのymlをgitで管理するっていう辺りはansibleとかと同じ感覚で良さそう。

やったこと

Udemyの講座の通りにローカル環境でコマンド打ってみた。

セットアップ

まずPCにvirtual boxをインストールして

brew install minikube
minikube start --driver=virtualbox

でminikubeというシステムを使ってデモ環境を作れる。Virtual boxを使うけどコマンドは普通にホストOS(MacWindows)で動かすことができる。virtual boxは他の仮想環境でも代替可能。

環境を作った後は以下のように各リソースを作って動作確認してUdemyの添付のWebアプリをkubenetes上で動かしてブラウザからアクセスするところまで試した。

kubectl run \
    --port 8080 \
    --image gcr.io/google-samples/hello-app:1.0 \
    --restart Never \
    --dry-run \
    -o yaml \
    helloworld > pod.yaml


kubectl apply -f pod.yml

こんな感じでkubectlでリソースを作成、操作してさらに--dry-run -o yaml オプションをつけてコード化していく。基本各リソースでこれを繰り返して環境を作るのがやったこと。

今後

macの上で基本的なところを動かすことはできて一旦気は済んだんだけど、実際にAWSGCP使って動かそうと思うとまたいろいろ考えることありそうだな。。リソースも上記以外にもあるし、kubenetes利用を便利にしてくれる周辺ツールも知る必要ありそうだし、複数Nodeで動かした時のネットワークとか難しそうだし監視の仕組みとか考えなきゃいけないことめっちゃ多そう。