【Rails】カラム追加して、既存のレコードに特定の条件を付けてそのカラムを埋めるメモ

bookseriesという本のシリーズを管理するテーブルがあります。

このテーブルは本の様々な情報を持つbookテーブルと紐付いています。

bookseriesに出版社名のカラムであるpublisherを追加します。

このカラムはbookにある出版社名のカラムと同じレコードを持たせたい。

そんなときに既存のレコードに反映させる方法です。

結論から言うとrunnerを使って条件を書いて読み込ませればOKです。

適当なディレクトリにrunnerする用のファイルを作ります。

lib/addcolumn/publisher_series.rb

Bookseries.all.each do |series|
  if series.publisher.nil?
    series.update(publisher: Book.find_by(series: series.title).publisherName)
  end
end

そこで対象のレコードを全て繰り返すeach文を作り、既存のレコードであるnilを判別する条件式の中に対象をupdateする式を書きます。

その後runner

rails runner lib/addcolumn/publisher_series.rb

実行完了のメッセージが表示されたらrails cなどでレコードを確認してみるとできていると思います。

【Rails】S3とcarrierwaveの連携メモ

以前書いたS3で簡単なWebページを作るメモから参照し、S3を作成しておく。

以下S3を作成した前提でのRails側でのメモ

IAMユーザー作成

S3を操作するIAMユーザーを追加する。

ユーザー名を適当に、アクセスの種類は「プログラムによるアクセス」

アクセス権限は、既存のポリシーをアタッチ→S3と検索し「AmazonS3FullAccess」を選択

タグなどは設定せず作成。

キーとシークレットキーをメモしておく。

これでS3の操作を全て可能なユーザーが完成。

Rails

Gemの追記

gem "carrierwave"
gem "fog-aws"

libxml2が必要なので使っている環境によってインストールしておく。

僕はDockerだったのでDockerfileのファーストステージにて以下を追記しておいた。

RUN apk --update add --virtual=buildings \
  libxml2-dev \ #追記

app/uploaders/image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :fog

を書き換え。

画像データがカラムとしてあるモデルのRubyファイルに

mount_uploader :image, ImagesUploader

を追記

config/initializers/carrierwave.rbを新規作成

CarrierWave.configure do |config|
  config.fog_provider = 'fog/aws'
  config.fog_directory = 'S3のバケット名'
  config.fog_credentials = {
    provider:              'AWS',
    aws_access_key_id:     'IAMアクセスキー',
    aws_secret_access_key: 'IAMシークレットキー',
    region:                'S3のリージョン名',
  }
end

AWSのキーは環境変数やらcredentialとかで隠すこと。

以上で設定完了のはず。

【Docker】コマンド整理/まとめ

忘れたとき用のメモ。

オプションなどの意味も整理。

container/image周り

※コマンドのdocker container/image などのcontainer/imageは省略できたりするが、敢えて省略しないほうがどういうコマンドを打っているのかがわかりやすいため、長い方が推奨されている。

docker container run イメージ名

指定したイメージからコンテナを起動する。

イメージ名の後ろに:タグを入力可能。

docker container run -it イメージ名 bash

対話的な入力が必要なbashプロセスを実行できる。

-itは対話的な入力をするというオプション。

-p ホスト側ポート:コンテナ側ポート

とすることでポートフォワーディングができる。

ポートフォワーディングとは、ホストマシンのポートとコンテナポートを紐付けるもの。

例えばコンテナ内に公開されたポートがあったとしてもそれはコンテナポートと呼ばれるもので、コンテナの外からは利用することができない。(コンテナ内からならOK)

仮にHTTPリクエストを受けるようなアプリケーションの場合、外からのリクエストをコンテナ内まで到達させる必要がある。

そこで利用するのがポートフォワーディングという機能。

この機能を使うことで、ホストマシンのポートをコンテナポートに紐付け、通信することができる。

docker container run -d -p 9000:8000

上のようにした場合、ホストマシンのポート9000へ何らかを送信すると、コンテナポートの8000へ行き着く。localhost:9000へgetリクエストを送るとコンテナポートの8000に送ったことになる。

因みにホストマシン側のポートは省略することができ、その場合は空いているポートが自動的に割り当てられる。どのポートに割り当てられたかは、後述するdocker container lsで確認できる。

docker container exec -it コンテナID bash

起動しているコンテナにbashで入る。

docker container ls -a

コンテナ一覧表示

-aを付けない場合は実行中のコンテナのみを表示する。

docker container stop コンテナ名 #コンテナの停止
docker container rm コンテナ名 #コンテナの削除
docker container restart #コンテナ再起動
docker image pull イメージ名

DockerHubからイメージをローカルに取得。

runをしたとき、イメージを取得していなかったら、自動でpullが実行されるので、このコマンドを実行する機会は少ない。

docker search イメージ名

イメージの検索

docker images

現在ローカルにあるイメージの一覧を表示

docker image build

Dockerfileからdocker imageを作成。

-t 名前 でimageに名前をつけれる。タグ名の指定も可能、省略した場合はlatestになる。

DockerHubに上げる場合は後述する命名方法に則って付ける。

さらにその後にはDockerfileを配置しているディレクトリのパスを記載する。

現在の場所であればドットを入れる。

docker image build ディレクトリの起点場所 -t イメージ名:タグ名

docker image rm イメージ名 #イメージの削除

DockerHub関連

docker login

dockerhubへログイン

usernameとpassword入力を促される。

docker image tag 変更するイメージのイメージ名 変更後のイメージ名(username/イメージ名)

Dockerhubにイメージを上げるとき、イメージを命名する例。

username/イメージ名 という形がDockerhubの命名規則なので、既にローカルに存在するイメージをDockerhubに上げる場合は、一度こういった命名のイメージを作る。

docker image push username/イメージ名

上のtagを用いて作ったimageをアップロードする。

docker image pull username/イメージ名

DockerHubから作成したイメージの取得。

そのままrunでも可

DockerfileのDSL

必須なものだけリストアップ。

  • FROM…ベースとなるDockerImageの指定(普通は公式提供のImageを使用する) ここで指定したImageはベースイメージと呼ばれる。

  • ENV…Docker内で使用する環境変数の定義 ( 例:ENV PASS_ENV=abcde )

  • WORKDIR…Dockerfileでコマンド実行時に基準となるディレクトリを指定する。

  • COPY…Docker内へファイルやディレクトリをコピーする。 ( 例:COPY ホスト側のディレクトリ Docker側のディレクトリ )

  • RUN…Docker内でコマンドを実行する。

  • USER…作成したDockerImageを起動したとき、ログインするユーザーを指定する。 デフォルトではrootが設定されている。

  • CMD…Docker起動時に実行されるコマンドを定義する。 ここで定義したコマンドが実行されている時間=コンテナがrunningの状態である時間 コマンドは配列のような形で各。

    $ go run /echo/main.go

    であれば

    CMD ["go", "run", "/echo/main.go"]

    のように書く。

ここから重要度が低かったり、扱いを選んだり、可読性を考えるDSL

  • EXPOSE…Dockerがどこのポートを使用するかを記述する。 指定したポートをホスト側で公開するにはrun使用時に-Pを付ける必要がある。 ※書いておくと読みやすい。

    docker run -P nginx

  • VOLUME…Volumeを作成する。

  • ARGS…Dockerfileビルド時、変数を使用するためのコマンド。 ※複雑になるので、基本使わないほうが良い。

  • ADD…COPYの上位互換。COPYと同じコピー機能、URL指定でそのURLからファイルダウンロードしコピー、そのファイルがtagかtag.gzのときは解凍する。 ※COPYを使えるならCOPYを使うべき。URLを指定すると、もしそのURLが変わってしまったときなど複雑になったりするので、なるべく使わない方が良い。

  • ENTRYPOINT…コマンドの実行。docker run時に指定したコマンドをこれの引数として使う。

    ENTRYPOINT ["echo"]

    $ docker run イメージ名 "hello" hello

    ※基本、CMDを使うほうが良い。

ネットワーク関連

docker network create 任意のネットワーク名

driverがbridgeの任意の名前のネットワークが作成される。

docker network ls

network一覧表示

docker run --name nginx --network=ネットワーク名 -d nginx

Nginxを任意のネットワークに参加させるコマンド例

docker network inspect ネットワーク名

ネットワークの詳細表示

Volume関連

docker volume ls

volume一覧

docker volume inspect VOLUME名

対象としたVolumeの詳細を確認

docker-machine

docker-machine ls

docker-machineの一覧表示

状態を確認できる。

docker-machine create --driver 仮想化マシンのドライバ名 マシンに付けたい名前

docker-machineの作成。

windowsでは基本hypervを指定する。

macだとvirtualbox

docker-machine env マシン名

一番下に対象にするdocker-machineをACTIVEにするコマンドが表示される。

-uを付けるとACTIVEを外すコマンドが表示される。

docker-machine start/stop マシン名

開始、停止

docker-machine ip マシン名

ip確認

docker-machine rm マシン名

マシンの削除、この後にy/Nの確認が行われる。

【Docker】Volumeについてのメモ

コンテナのライフサイクルでの終了と共に、コンテナ上のファイルは全て消えてしまうので、それを防ぎたいときのためにコンテナ外に管理できるファイルのことボリュームと言う。

docker container run -v ホストのパス:コンテナのパス runするイメージ名など

こうすることで、指定したホスト側のパスをコンテナ側のパスと共有できる。

ちなみにホスト側のパスは省略することが可能で、

docker container run -v コンテナ側のパス runするイメージ名など

としてあげると、ホスト側のパスはDocker上に自動で割り当てられる。自動で割り当てられたホスト側のボリュームは/var/lib/docker/volumesとかになるっぽい。

WindowsMacのDockerだとハイパーバイザ型の軽量Linuxを立ち上げ、その上でコンテナを動かしているため、Windowsの/var/lib/docker/volumesを確認しても存在していない。軽量Linux側のディレクトリに存在している。

docker-composeでボリュームを指定するときも基本は同じで、

volumes:
  - ホスト側のパス:コンテナ側のパス
  #または
  - コンテナ側のパス

とする。

ボリュームには名前をつけることができ、ボリュームのパスを指定するときに

ボリューム名:コンテナ側のパス

とすることで、名前をつけれる。

名前を付けなかった場合は、適当な文字列で自動的に名前が付けられるので非常に分かりづらい。

(docker volume lsで確認できる)

名前付きのボリュームは複数のサービスを跨ることが可能。

docker-composeで名前付きのボリュームを作成するときは、トップレベルでボリューム名を指定しておく。

version: '3'

services:
  web: #省略

  db:
    volumes:
      - mysql_data:/var/lib/mysql
volumes:
  mysql_data:

【Docker】AWSでDocker-machineを動かす手順

IAMでユーザーを作成する。

(プログラムによるアクセス→既存のポリシー→ AdministratorAccess→作成)

アクセスキーとシークレットキーをコピー

ローカルにフォルダを作り、credentialsファイルを作成。

[default]
aws_access_key_id = XXX
aws_secret_access_key = XXX

そこに先程のキーを記述。

docker-machine create --driver amazonec2 --amazonec2-open-port 8000 --amazonec2-region ap-northeast-1 aws-sandbox

これでawsのDocker-machineを作成する。

envコマンドでActive対象をAWSにし、使用するコンテナをrunする。

【AWS】S3を簡易的なWebサーバーとして機能させるメモ

AWSのマネージドサービスであるS3を簡単なWebサーバーとして機能させるメモになります。

あくまで学習の一環です。

S3のファイル置き場のことをS3バケットと言います。

ダッシュボードでの設定

S3のダッシュボードで、作成を押す。

パケット名(ドメイン名でアクセスしたいときはそのドメイン名で設定する。)を指定し、作成を押す。

(次へを押すと細かいオプションを設定できる。)

Webサーバーとして機能させる

ダッシュボードでパケット名を押しプロパティへ、Static Website Hostingを設定する。

これは、Webサーバーとしての機能を有効にさせる設定。

「このパケットを使用してウェブサイトをホストする」を選択

インデックスドキュメント(URLがスラッシュで終わるとき返すファイル)はindex.html

エラードキュメント(エラー発生時に返すファイル)はerror.htmlとかに各自設定する。

リダイレクトルール(指定したパスにアクセスしたとき、他のURLにリダイレクトさせる設定)は空欄で。

匿名アクセス可能にする

匿名アクセスを可能にするには、既存のポリシーでは設定できないので、カスタムポリシーを設定する。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/WebsiteAccessPermissionsReqd.html

にあるJSONデータの

{
  "Version":"2012-10-17",
  "Statement":[{
    "Sid":"PublicReadGetObject",
        "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::example-bucket/*"
      ]
    }
  ]
}

Resourceをカスタマイズする必要がある。

arn:aws:s3:リージョン名:アカウント:バケット名:パス名

:となっているのは指定しないという意味。*は全てという意味。

上のだとリージョン名とアカウント名が指定されていない状態。

ここではバケット名だけ、自分が指定したものにすればOK。

匿名アクセスのポリシーを設定できるようにする。

先程のプロパティの右にあるアクセス権限→ブロックパブリック→編集→上2つにチェック

更に上のバケットポリシーに先程のコードを入力。

ダッシュボードの概要から適当なファイルをアップロード。

http://www.バケット名.s3-website-ap-northeast-1.amazonaws.com/

でアクセス。

【AWS】fargateにALBを設定する

既にRoute 53でドメインを取得したり、証明書の発行が済んでいる前提。

EC2ダッシュボードからロードバランサーへ進み、作成を押す。

ALB選択し、各種設定をしていく。

ロードバランサーの設定

適当な名前を付け、インターネット向けを選択。

今回はHTTPS通信を可能にしたいものなので、リスナーのプロトコルHTTPSの443番ポートに。

アベイラビリティーゾーンはとりあえず全てを選択する。

セキュリティ設定の構成

基本デフォルトのままでいい。

ACMからの発行された対象の証明書を選択していることを確認。

セキュリティグループの設定

ロードバランサー用のセキュリティグループがないのであれば、新しいセキュリティグループを作成を押し、次へ。

ルーティングの設定

ALBの配下にある対象のインスタンスだったり、Fargateなどの設定を行う。

ターゲットの種類をIPにする。(EC2インスタンスの場合はインスタンス

ALBとFargateの通信なので、ここでのプロトコルはHTTPの80番ポートに設定する。

※もし、ALBの作成後にターゲットグループにある登録したターゲットのステータスがhealth checks failed with these codes: [数字]みたいな風になっていたら、下のヘルスチェックの詳細設定から成功コードを表示された数字にしてみる。

ターゲットの登録

ALBと結びつけるターゲットを選択する。

Fatgateの起動しているタスクのプライベートIPを入力しておく。

これで作成する。

次はRoute 53で取得したドメインを使ってHTTPS通信を行うための設定

Route 53のダッシュボードから名前がwww.ドメイン名と登録した箇所を押し、エイリアスをはいに設定、エイリアス先から先程作成したALBを選びレコードセットを保存する。

Fargateの固定IPについて

現状、FargateのIPを固定化する(ElasticIPを割り当てる)ことは出来ないっぽいので

タスクが入れ替わる度にプライベート、パブリックの両方のIPが動的変化します。

無理やり固定化するためにはNATゲートウェイなどを使えばできるそうですが

https://qiita.com/tonishy/items/810950dec4f1ae0d761f

結構費用がかかるらしいので、手を出しづらい部分であります。

一応タスクが変化し、IPが変わったときの対処としては

EC2ダッシュボードからロードバランシングのターゲットグループ、

ターゲットタブから編集を押し、新しいタスクのプライベートIPアドレスを登録し、既存のものは解除してあげれば大丈夫です。ただ、これをすると反映には多少時間がかかるみたいなので、ElasticIPを簡単に割り当てればなあと思います…。