20200118のRubyに関する記事は29件です。

独学ではじめてAWS(EC2)にデプロイする方法⑩(macでNginxのインストールと設定)

Nginx

Webサーバの一種であるNginxの導入と設定を行います。
nginxは静的コンテンツ(つまりサーバ上のファイル)を高速に配信するように設計されている。
ユーザーのリクエストに対して静的コンテンツの取り出し処理を行い、そして動的コンテンツの生成をアプリケーションサーバに依頼することが可能

Nginxをインストール

下記のコマンドでインストール

[ec2-user@ip-172-31-25-189 ~]$ sudo yum -y install nginx

Nginxの設定ファイルを編集

[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf

下記を貼り付ける
(ディレクトリの場所などは、自分にあった場所を指定してください)

rails.conf
upstream app_server {
  # Unicornと連携させるための設定。
  # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく
  server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP;

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際のrootディレクトリ
  root /var/www/〇〇〇〇〇<アプリケーション名>/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}
  • 3行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。
  • 11行目の<Elastic IP>となっている箇所も同様に、ご自身のものに変更してください。
  • 14行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。

Nginxの権限を変更

POSTメソッドでもエラーが出ないようにするために、下記のコマンドも実行してください。

[ec2-user@ip-172-31-25-189 ~]$ cd /var/lib
[ec2-user@ip-172-31-25-189 lib]$ sudo chmod -R 775 nginx  

Nginxを再起動して設定ファイルを再読み込み

[ec2-user@ip-172-31-25-189 lib]$ cd ~
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart

ローカルでunicorn.rb修正

listen 3000

↓以下のように修正

listen "#{app_path}/tmp/sockets/unicorn.sock"

Githubで変更点をpushしたら、本番環境でも反映させます。

ターミナル(EC2)
[ec2-user@ip-172-31-25-189 ~]$ cd /var/www/アプリ名
[ec2-user@ip-172-31-23-189 <アプリ名>]$ git pull origin master

Unicornを再起動

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

続いて、unicorn_rails master(一番上)のプロセスをkillします。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID(上のコードでは17877)>

unicornを起動します

[ec2-user@ip-172-31-23-189 <アプリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

ブラウザからElastic IPでアクセス

https:// (Elastic IP)

これでサイトが表示されず、下記が表示されたら、、、、、、、、、

スクリーンショット 2020-01-18 23.50.33.png

もう一度、下記をやり直してください。

Nginxの設定ファイルを編集

[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf

下記を貼り付ける
(ディレクトリの場所などは、自分にあった場所を指定してください)

rails.conf
upstream app_server {
  # Unicornと連携させるための設定。
  # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく
  server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP;

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際のrootディレクトリ
  root /var/www/〇〇〇〇〇<アプリケーション名>/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

これで無事にサイトが表示されたら、完了です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS(EC2)でNginxのrails.confを設定する方法

AWSのNginxを設定する際に、rails.confファイルの設定をします。

この方法の説明が意外とないので、説明していきます

Nginxの設定ファイルを編集

[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf

rails.confファイルが開かれたら、下記の記述をします。

rails.conf
upstream app_server {
  # Unicornと連携させるための設定。
  # アプリケーション名を自身のアプリ名に書き換えることに注意。
 server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP;

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際のrootディレクトリ
  root /var/www/〇〇〇〇〇<アプリケーション名>/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

3行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。
11行目の<Elastic IP>となっている箇所も同様に、ご自身のものに変更してください。
14行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。

これで設定ができます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kernel.#forkで作成した子プロセスをゾンビ化させない

背景

ジョブキューをさばくバッチ処理を開発していると、子プロセスを使って並列処理を実装したくなりました。
最大で10プロセスまで子プロセスを生成し10並列で処理できるように実装したは良いものの、
子プロセスがゾンビプロセス化してジョブキューをうまくさばくことができませんでした。

これまでなんとなくRubyでプロセスを扱ってきたので、これを機にいろいろ試してみました。

検証環境

  • OS
    • Debian GNU/Linux 9 (stretch)
    • Dockerコンテナで検証しました。
  • Ruby
    • 2.6.3

検証

以下、やったことを書いていきます。

親プロセス

手始めに親プロセスの確認。

root@05b9ab6e9fa3:~# irb
irb(main):001:0>
irb(main):002:0> Process.pid
=> 534
root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  1.2  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  3.7  0.8  90008 16596 pts/0    S+   12:23   0:00  \_ irb
:

親のpidが「534」であることが確認できました。

子プロセス

次に子プロセスの確認。

Kernel.#fork を使って、子プロセスを生成します。

irb(main):003:0> fork { sleep 60 }
=> 543
root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.4  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.9  0.8  90148 16596 pts/0    S+   12:23   0:00  \_ irb
root       543  0.0  0.5  90148 11396 pts/0    S+   12:25   0:00      \_ irb
:

子プロセスが生成できました。

ゾンビ化する子プロセス

しばらく時間をおいてプロセスを確認すると、子プロセスが になり、STATが Z+ になっていました。

root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.2  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.5  0.8  90148 16596 pts/0    S+   12:23   0:00  \_ irb
root       543  0.0  0.0      0     0 pts/0    Z+   12:25   0:00      \_ [irb] <defunct>
:

これは親プロセスが子プロセスを管理していないため、子プロセスがカーネルのキューに残り続けてしまっている状態のようです。

子プロセスをゾンビ状態から開放させてあげるためには、親プロセスにて Process.wait を読んであげると良いらしいのでやってみました。

irb(main):004:0> Process.wait
=> 543
root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.0  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.2  0.8  90148 16664 pts/0    S+   12:23   0:00  \_ irb
:

子プロセスが無事に開放されましたね。

子プロセスをゾンビにさせない

子プロセスが終了するより先に、Process.#detach を呼んでみます。

irb(main):007:0> fork { sleep 60 }
=> 555
irb(main):008:0> Process.detach(555)
=> #<Process::Waiter:0x000055ca51dad5b0 run>
irb(main):009:0>

子プロセスの処理が終了する前にプロセスの状況を確認してみると、先ほどとは変わらないですね。

root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.0  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.1  0.8 157740 16724 pts/0    Sl+  12:23   0:00  \_ irb
root       555  0.0  0.5  90148 11420 pts/0    S+   12:32   0:00      \_ irb
:

子プロセスの処理が終了した後にプロセスの状況を確認してみると...

root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.0  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.1  0.8 157740 16732 pts/0    S+   12:23   0:00  \_ irb
:

おー。ゾンビにならず無事に(?)子プロセスが終了しています。
ゾンビプロセスにさせたくないときは、子プロセスを生成した後すぐにデタッチしてあげると良いみたいですね。

子プロセスが終了した後に、Process.#detach を呼ぶとどうなるか

まずは子プロセスの生成。

irb(main):018:0> fork { sleep 60 }
=> 562

子プロセスがゾンビ化するのを待ちます。

root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.0  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.0  0.8 157888 16836 pts/0    S+   12:23   0:00  \_ irb
root       562  0.0  0.0      0     0 pts/0    Z+   12:38   0:00      \_ [irb] <defunct>
:

親プロセスで Process.#detach を呼び出します。

irb(main):020:0> Process.detach(562)
=> #<Process::Waiter:0x000055ca51dc8ec8 run>
irb(main):021:0>

プロセスの状態を確認すると

root@05b9ab6e9fa3:~# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529  0.0  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534  0.0  0.8 157888 16860 pts/0    S+   12:23   0:00  \_ irb
:

子プロセスが消えてますね。
まあ、これはそうなるような気がしてました。

スレッドの状態を確認する

irb(main):023:0> fork { sleep 60 }
=> 577
root@05b9ab6e9fa3:~# ps aux -L
USER       PID   LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529   529  0.0    1  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534   534  0.0    1  0.8 157888 16860 pts/0    S+   12:23   0:00 irb
root       577   577  0.0    1  0.5 157888 11636 pts/0    S+   12:43   0:00 irb

子プロセスが終了する前に、Process.#detach を呼びます。

irb(main):024:0> Process.detach(577)
=> #<Process::Waiter:0x000055ca51dd4b60 run>

スレッドを確認すると、

root@05b9ab6e9fa3:~# ps aux -L
USER       PID   LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529   529  0.0    1  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534   534  0.0    2  0.8 157888 16904 pts/0    Sl+  12:23   0:00 irb
root       534   580  0.0    2  0.8 157888 16904 pts/0    Sl+  12:43   0:00 irb
root       577   577  0.0    1  0.5 157888 11636 pts/0    S+   12:43   0:00 irb
:

PIDが534のプロセスが2プロセスになってます。
ps コマンドの -L オプションで スレッドも表示するようにしているためです。

子プロセスが終了すると、

root@05b9ab6e9fa3:~# ps aux -L
USER       PID   LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
:
root       529   529  0.0    1  0.1  18188  3216 pts/0    Ss   12:23   0:00 /bin/bash
root       534   534  0.0    1  0.8 157888 16904 pts/0    S+   12:23   0:00 irb
:

子プロセスが消え、親プロセスも1スレッドに戻っていることが確認できました。

この状態から、親プロセスで Process.#wait を呼ぶと

irb(main):026:0> Process.wait
Traceback (most recent call last):
        5: from /usr/local/bin/irb:23:in `<main>'
        4: from /usr/local/bin/irb:23:in `load'
        3: from /usr/local/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2:
       from (irb):26
        1: from (irb):26:in `wait'
Errno::ECHILD (No child processes)

Errno::ECHILD エラーが発生してますね。
子プロセスがいなくなっているのだから、当然ですね。

同じことを、Rubyのプログラムからも確認してみました。

irb(main):043:0> fork { sleep 60 }
=> 585
irb(main):044:0>
irb(main):045:0> Process.detach(585)
=> #<Process::Waiter:0x000055ca51b51230 run>
irb(main):046:0>
irb(main):047:0> Thread.list
=> [#<Thread:0x000055ca5174f2b8 run>, #<Process::Waiter:0x000055ca51b51230 sleep>]
irb(main):048:0>
irb(main):049:0>

# ここで子プロセスが終了。

irb(main):050:0> Thread.list
=> [#<Thread:0x000055ca5174f2b8 run>]
irb(main):051:0>

スレッドが2になり、子プロセスが終了するとスレッド数も1に戻っていることがわかります。

Process.#detach と `Process.#wait を同時に呼ぶとどうなるか

irb(main):034:0> fork { sleep 60 }
=> 583
irb(main):035:0> Process.detach(583)
=> #<Process::Waiter:0x000055ca51dff518 run>
irb(main):036:0>
irb(main):037:0> Process.wait

Traceback (most recent call last):
        5: from /usr/local/bin/irb:23:in `<main>'
        4: from /usr/local/bin/irb:23:in `load'
        3: from /usr/local/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):37
        1: from (irb):37:in `wait'
Errno::ECHILD (No child processes)

Process.wait を読んだ直後は、待ち状態に入りました。
子プロセスの処理が終了したタイミングで Errno::ECHILD エラーが発生しました。

Process.#detach と `Process.#wait のどちらか一方を呼び出すようにするのが良さそうです。

結論

forkしたあと、すぐに Process.#detach を呼び出し、スレッド数を監視することで子プロセス数の制御するのが良さそうな気がしました。

このようなユースケースではどうやってプロセス管理するのがいいんでしょうね。

他の方法でやってる方がいらっしゃったら教えてください?

参考

プロセスの適切な扱い方を再確認した

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Github Actionsを使ってAWS Lambda関数を更新する

モチベーション

AWSコンソールを開いたり、AWS CLIを使わずに、gitの操作だけでAWS Lambda関数のデプロイを完了します。

近年、Github AcitonsというGithub純正のCI/CDツールがリリースされました。
これを使って、Githubで管理しているAWS Lambda関数の変更を、AWSに反映します。

先駆者

検索すると、AWS Lambda関数をデプロイするGithub Acitonsがいくつか公開されているのが見つかります。1

例えば Deploy AWS Lambda functionソースコードを見てみましょう。aws-sdkを使っているのがわかります。2
その中でもupdate_function_codeメソッドを使っています。3

同様にaws-sdkを使えば上手くいきそうです。
今回はRuby用のaws-sdk-lambda gemを使います。

準備

IAMユーザー

万が一、AWSのIDとパスワードが漏れたときに、該アカウントだけを停止できるように、AWS上にdeploy専用のIAMユーザーを作成します。
必要なIAMポリシーは次のとおりです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "lambda:UpdateFunctionCode",
            "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXX:function:tange"
        }
    ]
}

Actionには今回使いたいupdate_function_codeメソッドを表すlambda:UpdateFunctionCodeを指定します。
Resourceには、更新対象のLambda関数のARNの値を指定します。ここでは
arn:aws:lambda:ap-northeast-1:XXXXXXX:function:tangeを指定しました。

Github Secrets

Github Actionsには、リポジトリに設定されたパスワードのような秘密情報を参照する機能があります。
IAMのaccess_key_idsecret_access_keyをGithub Actionsから参照するのに使います。

手順は暗号化されたシークレットの作成と利用 - GitHub ヘルプを参照してください。

Github Actions

完成形

最初に完成形を示します。これをLambda関数を管理しているリポジトリに追加すると、Github Acitonsは動作します。

.github/workflows/deploy_lambda.yml
name: Ruby

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Set up Ruby 2.5
      uses: actions/setup-ruby@v1
      with:
        ruby-version: 2.5.x
    - name: bundle install
      run: |
        gem install bundler
        bundle install --deployment
    - name: Zip
      run: |
        zip deploy_package lambda_function.rb -r vendor
    - name: Deploy
      env:
        access_key_id: ${{ secrets.access_key_id }}
        secret_access_key: ${{ secrets.secret_access_key }}
      run: |
        gem install aws-sdk-lambda
        bin/deploy

各ジョブの解説

リポジトリへのpushに応じてGithub Actionsを起動する

on: [push]

onには色々なトリガーが指定できます。
詳しくはワークフローをトリガーするイベント - GitHub ヘルプを見てください。

ソースコードをチェックアウトする

- uses: actions/checkout@v1

Ruby 2.5の環境を作る

AWS Lambdaはruby 2.5をサポートしています。4

- name: Set up Ruby 2.5
  uses: actions/setup-ruby@v1
  with:
    ruby-version: 2.5.x

依存ライブラリをダウンロードする

- name: bundle install
  run: |
    gem install bundler
    bundle install --deployment

--deploymentをつけると、依存ライブラリはvendorディレクトリ配下に格納されます。

zip圧縮

zipコマンドで必要なファイルを1つのzipファイルに纏めます。

- name: Zip
  run: |
    zip deploy_package lambda_function.rb -r vendor

deploy_packageは作成するzipファイル名です。

lambda_function.rbはzipファイルに含めるファイル名です。
AWS LambdaでRubyランタイムを使うときのデフォルトファイル名がlambda_function.rbです。
他に必要なファイルがあれば、空白で区切って続けて書いてください。

-r vendorbundle installコマンドで保存した依存ライブラリをzipファイルに入れるためにつけています。
他に必要なディレクトリがあれば追加してください。

AWSにアップロード

- name: Deploy
  env:
    access_key_id: ${{ secrets.access_key_id }}
    secret_access_key: ${{ secrets.secret_access_key }}
  run: |
    gem install aws-sdk-lambda
    bin/deploy

Github Secretsに設定した秘密情報を読み込みます。

env:
  access_key_id: ${{ secrets.access_key_id }}
  secret_access_key: ${{ secrets.secret_access_key }}

${{ secrets.access_key_id }} がGithub Secretsを参照している箇所です。

デプロイに必要なaws-sdk-lambda gemをインストールして、デプロイを実行します。

run: |
  gem install aws-sdk-lambda
  bin/deploy

bin/deployはRubyスクリプトです。

bin/deploy
#!/usr/bin/env ruby
require "aws-sdk-lambda"

client = Aws::Lambda::Client.new region: "ap-northeast-1",
                                 access_key_id: ENV["access_key_id"],
                                 secret_access_key: ENV["secret_access_key"]

zip_file = File.open "deploy_package.zip", "r"
client.update_function_code function_name: "tange", zip_file: zip_file

Aws::Lambda::Client#update_function_codeを使って、AWS Lambda関数を更新します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Github Actionsを使ってRuby製のAWS Lambda関数を更新する

モチベーション

AWSコンソールを開いたり、AWS CLIを使わずに、gitの操作だけでAWS Lambda関数のデプロイを完了します。

近年、Github AcitonsというGithub純正のCI/CDツールがリリースされました。
これを使って、Githubで管理しているAWS Lambda関数の変更を、AWSに反映します。

前提条件

今回はRubyで作成されたAWS Lambda関数を更新します。
Lambda関数とデプロイスクリプトが同じ言語だとメンテナンスが楽なので、デプロイにもRubyを使います。

先駆者

検索すると、AWS Lambda関数をデプロイするGithub Acitonsがいくつか公開されているのが見つかります。1

例えば Deploy AWS Lambda functionソースコードを見てみましょう。aws-sdkを使っているのがわかります。2
その中でもupdate_function_codeメソッドを使っています。3

引数にはZipファイルを指定しています。
AWSコンソールでAWS Lambda関数を更新するときと同様に、zipファイルを作って更新すれば良さそうです。

Ruby用のaws-sdk-lambda gemを使います。

準備

IAMユーザー

万が一、AWSのIDとパスワードが漏れたときに、該アカウントだけを停止できるように、AWS上にdeploy専用のIAMユーザーを作成します。
必要なIAMポリシーは次のとおりです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "lambda:UpdateFunctionCode",
            "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXX:function:tange"
        }
    ]
}

Actionには今回使いたいupdate_function_codeメソッドを表すlambda:UpdateFunctionCodeを指定します。
Resourceには、更新対象のLambda関数のARNの値を指定します。ここでは
arn:aws:lambda:ap-northeast-1:XXXXXXX:function:tangeを指定しました。

Github Secrets

Github Actionsには、リポジトリに設定されたパスワードのような秘密情報を参照する機能があります。
IAMのaccess_key_idsecret_access_keyをGithub Actionsから参照するのに使います。

手順は暗号化されたシークレットの作成と利用 - GitHub ヘルプを参照してください。

Github Actions

完成形

最初に完成形を示します。これをLambda関数を管理しているリポジトリに追加すると、Github Acitonsは動作します。

.github/workflows/deploy_lambda.yml
name: Ruby

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1

    - name: Ruby 2.5の環境を作る
      uses: actions/setup-ruby@v1
      with:
        ruby-version: 2.5.x

    - name: 依存gemをダウンロード
      run: |
        gem install bundler
        bundle config set deployment 'true'
        bundle install

    - name: zip圧縮
      run: |
        zip deploy_package lambda_function.rb -r vendor

    - name: AWSにアップロード
      env:
        access_key_id: ${{ secrets.access_key_id }}
        secret_access_key: ${{ secrets.secret_access_key }}
      run: |
        gem install aws-sdk-lambda
        bin/deploy

各ジョブの解説

リポジトリへのpushに応じてGithub Actionsを起動する

on: [push]

onには色々なトリガーが指定できます。
詳しくはワークフローをトリガーするイベント - GitHub ヘルプを見てください。

ソースコードをチェックアウトする

- uses: actions/checkout@v1

Ruby 2.5の環境を作る

AWS Lambdaはruby 2.5をサポートしています。4

- name: Ruby 2.5の環境を作る
  uses: actions/setup-ruby@v1
  with:
    ruby-version: 2.5.x

依存gemをダウンロード

- name: bundle install
  run: |
    gem install bundler
    bundle config set deployment 'true'
    bundle install

AWS Lambdaでは、関数は実行可能は状態でアップロードする必要があります。
つまりアップロードzipファイルには依存ライブラリも入れる必要があります。
zipファイルに入れやすくするため、依存gemをローカルディレクトリにインストールします。

bundle config set deployment 'true'を設定すると、依存ライブラリはvendorディレクトリ配下に格納されます。

zip圧縮

zipコマンドで必要なファイルを1つのzipファイルに纏めます。

- name: Zip
  run: |
    zip deploy_package lambda_function.rb -r vendor

deploy_packageは作成するzipファイル名です。

lambda_function.rbはzipファイルに含めるファイル名です。
AWS LambdaでRubyランタイムを使うときのデフォルトファイル名がlambda_function.rbです。
他に必要なファイルがあれば、空白で区切って続けて書いてください。

-r vendorbundle installコマンドで保存した依存ライブラリをzipファイルに入れるためにつけています。
他に必要なディレクトリがあれば追加してください。

AWSにアップロード

- name: Deploy
  env:
    access_key_id: ${{ secrets.access_key_id }}
    secret_access_key: ${{ secrets.secret_access_key }}
  run: |
    gem install aws-sdk-lambda
    bin/deploy

Github Secretsに設定した秘密情報を読み込みます。

env:
  access_key_id: ${{ secrets.access_key_id }}
  secret_access_key: ${{ secrets.secret_access_key }}

${{ secrets.access_key_id }} がGithub Secretsを参照している箇所です。

デプロイに必要なaws-sdk-lambda gemをインストールして、デプロイを実行します。

run: |
  gem install aws-sdk-lambda
  bin/deploy

bin/deployはRubyスクリプトです。

bin/deploy
#!/usr/bin/env ruby
require "aws-sdk-lambda"

client = Aws::Lambda::Client.new region: "ap-northeast-1",
                                 access_key_id: ENV["access_key_id"],
                                 secret_access_key: ENV["secret_access_key"]

zip_file = File.open "deploy_package.zip", "r"
client.update_function_code function_name: "tange", zip_file: zip_file

Aws::Lambda::Client#update_function_codeを使って、AWS Lambda関数を更新します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveRecord::AdapterNotSpecified: 'production' database is not configured. が表示された場合

アセットコンパイル時に下記を実行するが

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production

この際にエラーが表示される場合がある。

エラーが出る場合

ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test", "database", "username", "password", "socket"]

下記を修正してください
database.yamlに『 <<: *default 』を追記する
(もともとあるが、いらないだろうと思い消してしまうとエラーが表示される)

config/database.yml
production:
  <<: *default # ここが抜けているはず
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

追記したらpullして更新しましょう

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master

再度

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production

今度は成功するはずです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列の奇数の個数の取り出し

初めに

配列の中から奇数の個数を取り出す方法をわからなかった(odd?を初めて学んだ)ので記事にまとめました。

odd? メソッド

公式リファレンスによると

自身が奇数であれば真を返します。そうでない場合は偽を返します。

本題

[1, 2, 3, 4, 5, 6, 7] <= 配列  この中から奇数の個数4を取り出す

1. eachメソッドで数を取り出す

2. 取り出した数の個数を出す

3. 条件分岐で奇数のみの個数を出す

この順番で考えます

1. eachメソッドで数を取り出す

def numbers(nums)
  nums.each do |num|
    puts num
  end
end

numbers([1, 2, 3, 4, 5, 6, 7])

# 出力結果 => 1 2 3 4 5 6 7

2. 取り出した数の個数を出す

def numbers(nums)
  count = 0
  nums.each do |num|
    count += 1 #繰り返される度にcountが1増える
  end
  puts count
end

numbers([1, 2, 3, 4, 5, 6, 7])

# 出力結果 => 7

3. 条件分岐で奇数のみの個数を出す

def numbers(nums)
  count = 0
  nums.each do |num|
    if num.odd? #numが奇数の時trueを返す
      count += 1
    end
  end
  puts count
end

numbers([1, 2, 3, 4, 5, 6, 7])

# 出力結果 => 4

無事に奇数のみを取り出すことができました。

逆に偶数のみ取り出したいときはeven?メソッドがあります

最後に

公式リファレンスを見ると知らないことがたくさんあるので定期的に見ることが大事だと思いました。
最後まで読んでくださってありがとうございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Can't connect to local MySQL server through socket '/tmp/mysql.sock'が表示された場合

AWSのEC2にデプロイしようとした際に、下記エラーが表示された場合の対処方法をまとめたいと思います。
『Can't connect to local MySQL server through socket '/tmp/mysql.sock'』

原因

問題点としては、下記のsocketに接続できないのが問題

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock #ここに接続ができない

mysqlを再起動すると、/var/lib/mysql/mysql.sockが自動的に作成されるので、起動

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

1) MySQLの起動確認
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)
sudo service mysqld start

#再起動をさせたい場合は、
sudo service mysqld restart

改善があるか?確認

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)

database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください
database.ymlにsocketの記述漏れがあれば、エラーがおきます

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock
config/database.yml
production:
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>
 #ここのsocketが抜けていないか???
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Can't connect to local MySQL server through socket '/tmp/mysql.sock'が表示された場合(本番環境)

AWSのEC2にデプロイしようとした際に、下記エラーが表示された場合の対処方法をまとめたいと思います。
『Can't connect to local MySQL server through socket '/tmp/mysql.sock'』

原因

問題点としては、下記のsocketに接続できないのが問題

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock #ここに接続ができない

mysqlを再起動すると、/var/lib/mysql/mysql.sockが自動的に作成されるので、起動

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

1) MySQLの起動確認
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)
sudo service mysqld start

#再起動をさせたい場合は、
sudo service mysqld restart

改善があるか?確認

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)

database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください
database.ymlにsocketの記述漏れがあれば、エラーがおきます

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock
config/database.yml
production:
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>
 #ここのsocketが抜けていないか???
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails5.2のmaster.keyを本番環境(AWS EC2)に設定する方法

master.keyを作成していないとどうなるのか?

master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。

rails db:create RAILS_ENV=productionを実行

$ rails db:create RAILS_ENV=production

するとエラーが表示される

rails aborted!
NoMethodError: Cannot load database configuration:
undefined method `[]' for nil:NilClass

この'[]'はdatabase.ymlの下記が読み込めないために発生する。

database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

'[]'は、[:database]、[:username]、[:password]、[:socket]が読み込めないことを意味している。

なぜ読み込めないのか?

credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。

これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。

本番環境のshared/configにmaster.keyを作成

ローカル環境にある,master.keyの中身を確認する

rails newで作成された、ローカルのmaster.keyを確認する。

$ vi config/master.key

すると下記のようにmaster.keyの中身が表示されます。

fadfdfdgaf44623535y....

この表示された、master.keyの値をコピーしましょう

スクリーンショット 2020-01-18 18.20.47.png
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。

本番環境でmaster.keyを作成

EC2のアプリのconfigを開きましょう

#本番環境
[ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名]
[ec2-user@ip-172-31-23-189 <アプリ名>]$ cd config

そうしたら、本番環境上でmaster.keyを作成します

[ec2-user@ip-172-31-23-189 config]$ vi master.key
# ローカル環境のmaster.keyの値を入力
fsdgagaf08deg424~~~~~

画像だと下記のような画面になります。

スクリーンショット 2020-01-18 18.20.47.png
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。

『 esc 』ボタンを押した後、:wq入力して保存します

これで本番環境でもmaster.keyが設定されています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails5.2】master.keyを本番環境(AWS EC2)に設定する方法

master.keyを作成していないとどうなるのか?

master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。

rails db:create RAILS_ENV=productionを実行

$ rails db:create RAILS_ENV=production

するとエラーが表示される

rails aborted!
NoMethodError: Cannot load database configuration:
undefined method `[]' for nil:NilClass

この'[]'はdatabase.ymlの下記が読み込めないために発生する。

database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

'[]'は、[:database]、[:username]、[:password]、[:socket]などの環境変数が読み込めないことを意味している。

なぜ読み込めないのか?

credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。

これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。

本番環境のshared/configにmaster.keyを作成

ローカル環境にある,master.keyの中身を確認する

rails newで作成された、ローカルのmaster.keyを確認する。

$ vi config/master.key

すると下記のようにmaster.keyの中身が表示されます。

fadfdfdgaf44623535y....

この表示された、master.keyの値をコピーしましょう

スクリーンショット 2020-01-18 18.20.47.png
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。

本番環境でmaster.keyを作成

EC2のアプリのconfigを開きましょう

#本番環境
[ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名]
[ec2-user@ip-172-31-23-189 <アプリ名>]$ cd config

そうしたら、本番環境上でmaster.keyを作成します

[ec2-user@ip-172-31-23-189 config]$ vi master.key
# ローカル環境のmaster.keyの値を入力
fsdgagaf08deg424~~~~~

画像だと下記のような画面になります。

スクリーンショット 2020-01-18 18.20.47.png
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。

『 esc 』ボタンを押した後、:wq入力して保存します

これで本番環境でもmaster.keyが設定されています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails5.2】master.keyを本番環境(AWS EC2)に設定(追加作成)する方法

master.keyを作成していないとどうなるのか?

master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。

rails db:create RAILS_ENV=productionを実行

$ rails db:create RAILS_ENV=production

するとエラーが表示される

rails aborted!
NoMethodError: Cannot load database configuration:
undefined method `[]' for nil:NilClass

この'[]'はdatabase.ymlの下記が読み込めないために発生する。

database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

'[]'は、[:database]、[:username]、[:password]、[:socket]などの環境変数が読み込めないことを意味している。

なぜ読み込めないのか?

credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。

これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。

本番環境のshared/configにmaster.keyを作成

ローカル環境にある,master.keyの中身を確認する

rails newで作成された、ローカルのmaster.keyを確認する。

$ vi config/master.key

すると下記のようにmaster.keyの中身が表示されます。

fadfdfdgaf44623535y....

この表示された、master.keyの値をコピーしましょう

スクリーンショット 2020-01-18 18.20.47.png
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。

本番環境でmaster.keyを作成

EC2のアプリのconfigを開きましょう

#本番環境
[ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名]
[ec2-user@ip-172-31-23-189 <アプリ名>]$ cd config

そうしたら、本番環境上でmaster.keyを作成します

[ec2-user@ip-172-31-23-189 config]$ vi master.key
# ローカル環境のmaster.keyの値を入力
fsdgagaf08deg424~~~~~

画像だと下記のような画面になります。

スクリーンショット 2020-01-18 18.20.47.png
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。

『 esc 』ボタンを押した後、:wq入力して保存します

これで本番環境でもmaster.keyが設定されています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

The asset "" is not present in the asset pipeline

assetへのパイプラインがうまくいってない時に起こるエラーです。

config/envitonments/production.rbで

config.assets.compile = true

をして、再起動してとりあえずうまく行かない時は、

<%= image_tag user.image.to_s %>

みたいな記述をしていませんか。
特にbxsliderをお使いの初学者の方。
このままだとただの変数を入れているだけになるので
そういう場合は、

<%= image_tag '/assets/user.jpg' %>

みたいに「app/assets/images」ディレクトリに置いて呼び出すか。
refireのgemを使って呼び出せばうまく行きます。

<%= f.attachment_field :image %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

独学ではじめてAWSのEC2にデプロイする方法⑨(Railsの起動)

ポートの解放

config/unicorn.rb に listen 3000 と記述しましたが、これはRailsのサーバを3000番ポートで起動するということを意味するのでした。
HTTPがつながるように「ポート」を開放する必要があります。

手順

1.EC2を開く
スクリーンショット 2020-01-14 19.47.31.png
2. 『実行中のインスタンス』を開く
3. インスタンスを選択
スクリーンショット 2020-01-10 16.34.14.png
4. セキュリティグループの『launch-wizard-3』をクリック
スクリーンショット 2020-01-10 16.37.48.png
5. 下記の画面が表示される
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3435353430332f37323334663664362d323935342d626334662d643634662d3466633236353061303066312e706e67 (1).png
6.『 インバウンド 』を選択
スクリーンショット 2020-01-10 20.49.20.png
7. 『 編集 』をクリック
スクリーンショット 2020-01-10 20.57.06.png
8. 左下の『ルールの追加』をクリック
Image from Gyazo
9. タイプ:「カスタムTCPルール」、プロトコルを「TCP」、ポート範囲を「3000」、送信元を「カスタム」「0.0.0.0/0」に設定
スクリーンショット 2020-01-14 19.56.35.png
10. 画面左下の『 保存 』をクリック

Railsの起動

Rails 5.1以前の場合

database.ymlに下記を追加します

config/database.yml(ローカル)
production:
  <<: *default
  database: アプリ名
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

追記が完了したら、EC2でも反映させます。
EC2とGithubは接続できているため、git pullコマンドを利用します。

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master

データベースの作成をする

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

この際に下記の表示が出た場合、、、うまくいっていません。
スクリーンショット 2020-01-18 22.03.37.png

アプリのディレクトリを開いてからコマンドを実行しましょう

#うまくいかない = アプリ名を指定していない
[ec2-user@ip-172-31-23-189 ~( ここが指定されていない )]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

#アプリ名(リポジトリ)を指定しているのでちゃんと処理がされる
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'


rails db:migrateを実行して、migrationを完了させる。

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:migrate RAILS_ENV=production

エラーが出る場合

Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)
sudo service mysqld start

#再起動をさせたい場合は、
sudo service mysqld restart

というコマンドをターミナルから打ち込み、mysqlの起動を試してみましょう。

参考記事
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

ユニコーンを起動

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
[ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

Rails5.2以降の場合

credentials.ymlの設定

ターミナル(ローカル)
アプリ名 $ EDITOR=vim bin/rails credentials:edit

すると編集画面が表示されます。
しかし文字入力ができないので、
『 i 』を押して、----INSERT----モードに変更します

下記を入力します。

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock

passwordははじめてAWSでデプロイする方法⑤(EC2の環境構築、Ruby, MySQL)の『MySQLのrootパスワードの設定』で設定しています。

次に、database.ymlにcredential.ymlで設定した環境変数を記述します

config/database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

本番環境のshared/configにmaster.keyを作成

手順

ローカル環境にある,master.keyの中身を確認する

rails newで作成された、ローカルのmaster.keyを確認する。

$ vi config/master.key

すると下記のようにmaster.keyの中身が表示されます。

fadfdfdgaf44623535y....

この表示された、master.keyの値をコピーしましょう

スクリーンショット 2020-01-18 18.20.47.png
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。

本番環境でmaster.keyを作成

EC2のアプリのconfigを開きましょう

#本番環境
[ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名]
[ec2-user@ip-172-31-23-189 <アプリ名>]$ cd shared/config

そうしたら、本番環境上でmaster.keyを作成します

[ec2-user@ip-172-31-23-189 config]$ vi master.key
# ローカル環境のmaster.keyの値を入力
fsdgagaf08deg424~~~~~

画像だと下記のような画面になります。

スクリーンショット 2020-01-18 18.20.47.png
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。

『 esc 』ボタンを押した入力モードを終了
『 :wq 』入力して保存します

これで本番環境でもmaster.keyが設定されています。

ユニコーンを起動

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
[ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

エラーが発生した場合

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)
sudo service mysqld start

#再起動をさせたい場合は、
sudo service mysqld restart

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)

database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock
config/database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>
 #ここのsocketが抜けていないか???

サイトにアクセスしてみる

ブラウザで http://<サーバに紐付けたElastic IP>:3000/ にアクセスしてみましょう
ブラウザにCSSの反映されていない(ビューが崩れている)画面が表示されていれば成功です。

アセットコンパイルする

レイアウトが崩れてしまっているでしょう。

開発中には正常に表示されていたのに、本番ではうまく表示されないのはなぜでしょうか?

これは、開発中はアクセス毎にアセットファイル(画像・CSS・JSファイルの総称)を自動的にコンパイル(圧縮)する仕組みが備わっていますが、本番モードのときにはパフォーマンスのためアクセス毎には実行されないようになっているためです。

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production
成功した場合
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
I, [2020-01-18T12:51:01.4345644 #1265]  INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png
I, [2020-01-18T12:51:02.2615123#1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js
I, [2020-01-18T12:51:02.2626434 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz
I, [2020-01-18T12:51:08.484546 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css
I, [2020-01-18T12:51:08.485454 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gz

エラーが出る場合

ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test", "database", "username", "password", "socket"]

下記を修正してください

config/database.yml
production:
  <<: *default # ここが抜けているはず
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

追記したら

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master

再度

ターミナル(EC2)
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production

今度は成功するはずです

成功した場合
Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
I, [2020-01-18T12:51:01.4345644 #1265]  INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png
I, [2020-01-18T12:51:02.2615123#1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js
I, [2020-01-18T12:51:02.2626434 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz
I, [2020-01-18T12:51:08.484546 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css
I, [2020-01-18T12:51:08.485454 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gz

Railsの再起動

コンパイルが成功したら反映を確認するため、Railsを再起動します。しかし、まずは今動いているUnicornをストップします。

EC2のターミナルから以下のように入力します。「aux」と打っているのは、psコマンドのオプションです。表示結果を見やすくしてくれます。また、| grep unicornとしているのはpsコマンドの結果からunicorn関連のプロセスのみを抽出するためです。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

大事なのは左から2番目の列です。ここに表示されるのがプロセスのid、つまりPIDになります。
「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体です。この時のPIDは、17877となっています。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID>

killコマンド:現在動いているプロセスを停止させるためのコマンドです

再度、プロセスを表示させ終了できていることを確認しましょう。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn
...
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

3つあった項目が一つになっています

では、Railsを起動させましょう!

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

もう一度、ブラウザで http://<Elastic IP>:3000/ にアクセスしてみましょう。今度はレイアウト崩れも無くサイトが正常に表示されていることでしょう。

参考

【Rails5.2】credentials.yml.encとmaster.keyでのデプロイによる今までとの変更点
【備忘録】credentials.yml.encにdatabase設定を保存する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

content_tagでmodalやリンクを表示する

はじめに

RailsでWebサービスを構築していると、フロントのコードをサーバーサイドで実装する場面ってありますよね。(あんまりないか)
Railsにはcontent_tagというメソッドが用意されていて、フロントのコードをサーバーサイドで記述することができます。

content_tag

content_tagの引数は以下のように構成されています。

  • 第一引数: タグ
  • 第二引数: 内容
  • 第三引数: クラスなどのオプション
# divタグ生成
content_tag(:div, 'hoge', class: 'fuga')
# => <div class="fuga">hoge</div>

modalを表示するには

modal表示のサンプルです。

hoge_helper.rb
def show_modal_button
  content_tag(:a, class: 'btn btn-default form-control', data: { toggle: 'modal', target: '#hoge-modal' }) do
    concat render 'hoge-modal'
    concat 'モーダル表示'
end
hoge/_hoge_modal.html.haml
.modal.fade#hoge-modal
  .modal-dialog
    .modal-content
      .modal-header
        %h4.modal-title
          Title!
      .modal-body
        hogehogefugafuga
      .modal-footer
        .btn.btn-default.data{ dismiss: 'modal' }
          閉じる
hoge/show.html.haml
...
.show-modal
 = show_modal_button
...

リンクを作成する場合

content_tagはlink_toをそのまま扱えないので、以下のように書く必要があります。

fuga_helper.rb
content_tag(a:, class: 'fuga', href: 'https://www.hoge.fuga.com') do
  concat 'hoge&fugaへのリンクです!'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails使用時のデバッグで便利なメソッド

今日、久しぶりに使いたくなってなかなか思い出せなかったので念のためにQiitaにも書いておく。

そこそこの規模で開発していると、自分が今みているメソッドがどこから呼ばれているか分からない時たまにありませんか?
メタプログラミング的に書かれていたりしてgrepがなかなか上手くできないケースがあります。

そういう時に便利なのがrubyのcallerメソッド
https://magazine.rubyist.net/articles/0031/0031-BackTrace.html

一旦pryで止めて、callerメソッドを実行するとその前に実行されていたメソッドの歴史が表示されるので、今見ているメソッドがどこから呼ばれているかすぐにわかります。

いやー、思い出せてスッキリ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CentOS 8 で Ruby 2.5 から Ruby 2.6 へアップグレード(AppStream)

はじめに

Application Stream(AppStream)を利用してCentOS8にRuby2.6をアップグレードインストール
参考:ユーザー空間コンポーネントのインストール、管理、および削除 Red Hat Enterprise Linux 8 | Red Hat Customer Portal

サポート

各Streamのサポート期間はRed Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portalを参照。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

LOG

Ruby2.5(default)インストール

# cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

# yum install -y ruby
... 略

# ruby -v
ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux]

Stream切り替え

# yum distro-sync
# yum module reset ruby
# yum module enable ruby:2.6
# yum distro-sync

# ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rubyでFizzBuzz問題を解いてみる

fizzbuzz問題とは

プログラミングの基礎的な技術力を測るために用いられる有名な問題らしい。
とあるプログラミングスクールで出題され、「こんなの簡単じゃん」と思い解き始めると、
全く解けなかったため、解説していきます。

問題内容

1から100まで数を数える時に、3の倍数なら「fizz」、5の倍数なら「buzz」、ただし15の倍数なら「fizzbuzz」、それ以外はその数を答えるものです。

例)
1
2
Fizz
4
.
.

これを実現するコードを記述しなさい。
ただし、elsifは使用せずに。
という問題

回答

まずは、単純に1〜100を出力するコードを記載してみる。

sample.rb
array=[*1..100]
puts array

これで、1〜100までを出力できました。

ここから、
3の倍数なら「fizz」、
5の倍数なら「buzz」、
15の倍数なら「fizzbuzz」、
を出力出来るように変更していく。

まずはelsifありで、
each文↓

sample.rb
array=[*1..100]

array.each do |n|
  if n%15 == 0
    puts "FizzBuzz"
  elsif n%3 == 0
    puts "Fizz"
  elsif n%5 == 0
    puts "Buzz"
  else
    puts n
  end
end

for文↓

sample.rb
array=[*1..100]

for n in array
  if n%15==0
      puts "FizzBuzz"
  elsif n%3==0
      puts "Fizz"
  elsif n%5==0 
      puts "Buzz"
  else
      puts n
  end
end

while文↓

sample.rb
n=1
#nが100になるまで繰り返す
while n <=100

    if n%15==0
        puts "FizzBuzz"
    elsif n%3==0
        puts "Fizz"
    elsif n%5==0 
        puts "Buzz"
    else
        puts n
    end

    n +=1
end

elsifを使用せずに回答↓

sample.rb
n = 1
while n <= 100
  str = ""

  if n % 3 == 0 #① 3で割り切れたらstrに"fizz"を代入
    str = str + "fizz"
  end

  if n % 5 == 0 #② 5で割り切れたらstrに"buzz"を代入
    str = str + "buzz"
  end

  #①と②の結果が共にtrueであれば、strは"fizzbuzz"になる(15の倍数)

  if str == ""
    str = str + n.to_s
  #①と②の結果が共にfalseであれば、strにnの数値を代入(3と5でも割り切れない)
  end

  puts str
  n += 1
end

実行結果

1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
.
.

elsifは使用せずに、という意地悪な問題でしたが、
rubyのアルゴリズムを組む上でif文の基本が詰まった良い問題だと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CentOS 8にRuby 2.6をインストール(AppStream)

はじめに

Application Stream(AppStream)を利用してCentOS8にRuby2.6をインストール
参考:RHEL8のパッケージ構成 - BaseOSとApplication Stream - 赤帽エンジニアブログ

サポート

本手法で導入した場合、Red Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portalより、2021-11がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

LOG

インストール

# cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

# yum install -y @ruby:2.6/common
... 略

各種確認

# which ruby
/usr/bin/ruby

# ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]

# yum module info ruby:2.6
Failed to set locale, defaulting to C.UTF-8
Last metadata expiration check: 0:02:50 ago on Sat Jan 18 07:24:40 2020.
Name         : ruby
Stream       : 2.6 [e] [a]
Version      : 8010020191122185822
Context      : cdc1202b
Architecture : x86_64
Profiles     : common [i]
Repo         : AppStream
Summary      : An interpreter of object-oriented scripting language
Description  : Ruby is the interpreted scripting language for quick and easy object-oriented programming.  It has many features to process text files and to do system management tasks (as in Perl).  It is simple, straight-forward, and extensible.
Artifacts    : ruby-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-0:2.6.3-106.module_el8.1.0+249+93480f15.src
             : ruby-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : ruby-debuginfo-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-debuginfo-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : ruby-debugsource-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-debugsource-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : ruby-devel-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-devel-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : ruby-doc-0:2.6.3-106.module_el8.1.0+249+93480f15.noarch
             : ruby-libs-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-libs-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : ruby-libs-debuginfo-0:2.6.3-106.module_el8.1.0+249+93480f15.i686
             : ruby-libs-debuginfo-0:2.6.3-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-abrt-0:0.3.0-4.module_el8.1.0+249+93480f15.noarch
             : rubygem-abrt-0:0.3.0-4.module_el8.1.0+249+93480f15.src
             : rubygem-abrt-doc-0:0.3.0-4.module_el8.1.0+249+93480f15.noarch
             : rubygem-bigdecimal-0:1.4.1-106.module_el8.1.0+249+93480f15.i686
             : rubygem-bigdecimal-0:1.4.1-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-bigdecimal-debuginfo-0:1.4.1-106.module_el8.1.0+249+93480f15.i686
             : rubygem-bigdecimal-debuginfo-0:1.4.1-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-bson-0:4.5.0-1.module_el8.1.0+249+93480f15.src
             : rubygem-bson-0:4.5.0-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-bson-debuginfo-0:4.5.0-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-bson-debugsource-0:4.5.0-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-bson-doc-0:4.5.0-1.module_el8.1.0+249+93480f15.noarch
             : rubygem-bundler-0:1.17.2-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-did_you_mean-0:1.3.0-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-io-console-0:0.4.7-106.module_el8.1.0+249+93480f15.i686
             : rubygem-io-console-0:0.4.7-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-io-console-debuginfo-0:0.4.7-106.module_el8.1.0+249+93480f15.i686
             : rubygem-io-console-debuginfo-0:0.4.7-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-irb-0:1.0.0-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-json-0:2.1.0-106.module_el8.1.0+249+93480f15.i686
             : rubygem-json-0:2.1.0-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-json-debuginfo-0:2.1.0-106.module_el8.1.0+249+93480f15.i686
             : rubygem-json-debuginfo-0:2.1.0-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-minitest-0:5.11.3-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-mongo-0:2.8.0-1.module_el8.1.0+249+93480f15.noarch
             : rubygem-mongo-0:2.8.0-1.module_el8.1.0+249+93480f15.src
             : rubygem-mongo-doc-0:2.8.0-1.module_el8.1.0+249+93480f15.noarch
             : rubygem-mysql2-0:0.5.2-1.module_el8.1.0+249+93480f15.src
             : rubygem-mysql2-0:0.5.2-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-mysql2-debuginfo-0:0.5.2-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-mysql2-debugsource-0:0.5.2-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-mysql2-doc-0:0.5.2-1.module_el8.1.0+249+93480f15.noarch
             : rubygem-net-telnet-0:0.2.0-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-openssl-0:2.1.2-106.module_el8.1.0+249+93480f15.i686
             : rubygem-openssl-0:2.1.2-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-openssl-debuginfo-0:2.1.2-106.module_el8.1.0+249+93480f15.i686
             : rubygem-openssl-debuginfo-0:2.1.2-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-pg-0:1.1.4-1.module_el8.1.0+249+93480f15.src
             : rubygem-pg-0:1.1.4-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-pg-debuginfo-0:1.1.4-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-pg-debugsource-0:1.1.4-1.module_el8.1.0+249+93480f15.x86_64
             : rubygem-pg-doc-0:1.1.4-1.module_el8.1.0+249+93480f15.noarch
             : rubygem-power_assert-0:1.1.3-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-psych-0:3.1.0-106.module_el8.1.0+249+93480f15.i686
             : rubygem-psych-0:3.1.0-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-psych-debuginfo-0:3.1.0-106.module_el8.1.0+249+93480f15.i686
             : rubygem-psych-debuginfo-0:3.1.0-106.module_el8.1.0+249+93480f15.x86_64
             : rubygem-rake-0:12.3.2-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-rdoc-0:6.1.0-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-test-unit-0:3.2.9-106.module_el8.1.0+249+93480f15.noarch
             : rubygem-xmlrpc-0:0.3.0-106.module_el8.1.0+249+93480f15.noarch
             : rubygems-0:3.0.3-106.module_el8.1.0+249+93480f15.noarch
             : rubygems-devel-0:3.0.3-106.module_el8.1.0+249+93480f15.noarch

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアル第1章で勉強をブロックしたやつ

はじめに

この記事では私がRailsチュートリアルの第1章でつまづいた所を共有します。
個人的な備忘録ですが、プログラミング学習入門で人気のRailsなのでお役に立てればうれしいです!

実行環境

AWS Cloud9を使用しました。チュートリアルの手順通りに環境設定しました。

問題

Railsチュートリアル1.3.2で、

rails server

を実行し、アプリケーションをブラウザで開こうとしたところ、
まったく開きませんでした...

解決策

色々調べた結果、ブラウザに導入していた広告ブロックが邪魔をしていました。広告ブロックを停止するとブラウザでRailsのウェルカム画面が無事表示されました。

また、下図のような表示がずっとでていましたが、EC2を再起動すれば解決しました。
こちらの記事が参考になります。
Oops.png

まとめ

広告ブロックはプログラミング学習以外では非常に便利ですが、プログラミング学習するときは常時切っておくほうがよいかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby で C言語の enum っぽく連番定数を作る

この場合の「enumっぽい」というのは、下の C コードのように単に「整数を連番で入れた定数を作りたい」程度の意味です。

enum { // 曜日ごとに順番に 1, 2, 3, .... が割り振られる
    SUNDAY = 1,
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY
};

Ruby では言語としては enum は用意されていないので、通常の方法では下のように1つ1つ定数を定義することになります。

module Foo
  SUNDAY    = 1
  MONDAY    = 2
  TUESDAY   = 3
  WEDNESDAY = 4
  THURSDAY  = 5
  FRIDAY    = 6
  SATURDAY  = 7
end

曜日くらいならいいんですが、もっと大量の連番を作りたいときはこれでは大変ですね。

そんなわけで、Ruby でできるだけ手軽に enum っぽいことをする方法を考えてみました。

module Foo
  %i(
    SUNDAY
    MONDAY
    TUESDAY
    WEDNESDAY
    THURSDAY
    FRIDAY
    SATURDAY
  ).each.with_index(1){ |v, i| const_set(v, i) }
  # ruby2.7 なら { const_set(_1, _2) } でも行けますね
end

C の enum と違って途中から値を変更するということはできませんが、比較的手軽に実現できたのではないかと思います。もっとシンプルな方法があればぜひコメントお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Sorcery】よく使うメソッドまとめ

はじめに

SorceryのGitHubに書いてあることを日本語でまとめました。
公式GitHubではメソッド名をクリックすると定義のページに飛びます。

随時更新します。

メソッドについて・実際の使い方

require_login

ログインをしていないユーザーをアクション単位で弾く。
アクセスしようとしたURLをセッションに格納し、not_authenticatedを実行する。

hoges_controller.rb
before_action :require_login

アクションごとに変える場合は、only: :actionを付ける。
アクション内の分岐など、もっと細かい単位で弾きたい場合は後述のlogged_in?を使う。

not_authenticated

先ほどのrequire_loginが実行されたときに、このメソッドも実行される。
デフォルトではredirect_to root_pathと定義されているが、カスタマイズしたい場合はapplication_controllerで上書きをする。

application_controller.rb
class ApplicationController < ActionController::Base
  protected

  def not_authenticated
    redirect_to login_url, danger: 'ログインしてください'
  end
end

current_user

きっと一番よく使う。
現在ログイン中のUserを返す。コントローラ、ビューで使える。

logged_in?

現在ログイン中かどうか、true or falseで返す。コントローラ、ビューで使える。
ログインしているかどうかによって場合分けをしたいときに使うことが多い。

view.html.erb
<% if logged_in? %>
  <%= link_to 'プロフィール', user_url(current_user) %>
<% else %>
  <%= link_to 'ログイン', login_url %>
<% end %>

redirect_back_or_to(dafault_url, flash_hash = {})

ログインのアクションで使う。
require_loginのときにセッションに格納されたURLまたはデフォルトのURLにリダイレクトする。

user_sessions_controller.rb
class UserSessionsController < ApplicationController
  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_back_or_to root_url, success: 'ログインしました'
    else
      flash.now[:danger] = 'ログインに失敗しました'
      render :new
    end
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby 配列結合

環境

・ruby 2.7
・rails 5.1.6

配列結合

ary = ["a","b","c"]
p ary.join

=> "abc" #配列の中にある要素を全て結合

結合されている配列を一文字区切りにする

p ary.join(",")

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#Ruby + Faker で 16進数 の Mac アドレスを生成する例

require 'Faker'
# => false

Faker::Internet::mac_address
# => "ca:ea:fb:ab:cc:b9"
Faker::Internet::mac_address.upcase
# => "32:05:2B:AE:CB:59"

ruby的に頑張らなくても良かったんだ

Array.new(6) { Faker::Number.unique.hexadecimal(digits: 2).to_s.upcase }.join(':')
# => "1E:42:12:27:E2:CB"

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2949

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bundler が Ruby 2.7 で変な件

Ruby 2.7 で Bundler がらみの不可解な現象に遭遇している。

前提

この記事で述べる実験は 2020-01-17 時点のもの。

Ruby 2.6.5 と Ruby 2.7.0 の二つについて実験を行った。

Windows と macOS と CentOS で実験した。
Windows は RubyInstaller for Windows でインストールしたもの。他は rbenv でインストール。

Ruby 2.6.5 も 2.7.0 も,デフォルトの bundler gem は 2.1.2 だが,

gem update bundler

して,bundler 2.1.4 をインストールした。
したがって,どの OS,どの Ruby でも,2.1.2 と 2.1.4 が入った状態。

実験 1

まず,OS と Ruby バージョンに関わらず,端末で

bundle -v

とやったら

Bundler version 2.1.4

と表示された(当然)。

次に,

gem list bundler

とやったときの結果が意外だった。

macOS と CentOS の Ruby 2.7.0 でだけ

bundler (2.1.4)

と表示され,その他の OS,Ruby バージョンの組み合わせでは

bundler (2.1.4, default: 2.1.2)

と表示されたのだ。後者のほうがしかるべき表示のような気がする。
Ruby のバージョンだけで違いが生じるなら「Ruby 2.7 で仕様が変わったのかな」と思うところだが,Windows の場合,バージョンによる違いはない。

実験 2

以下のスクリプトを実行した。

gem "bundler"
require "bundler"

p Bundler::VERSION

すると,すべての組み合わせにおいて,「"2.1.4"」が表示された。
これは期待通り。
インストールされている最新版が require されるはずだから。

実験 3

前の実験をちょっと改変して,

require "bundler"

p Bundler::VERSION

としてみた。
すると今度は,どの OS でも,Ruby 2.6.5 では「"2.1.4"」と表示されるが,Ruby 2.7.0 では「"2.1.2"」と表示される。
え? 最新版じゃない?

これは何か Ruby 2.7 で仕様が変わったとした思えない。うーむ。

実験 4

まず,Gemfile に以下のようにだけ書く。

Gemfile
source "https://rubygems.org"

(なんか gem を指定してもいいのだが,何も書かなくても実験は可能)

そして,コマンドライン上で

bundle check

する。
そうすると,Gemfile.lock が出来る。
Ruby 2.6.5 でやっても,Ruby 2.7.0 でやっても,その末尾には

BUNDLED WITH
   2.1.4

と書かれる。
これは納得できる話だ。実験 1 で,bundle コマンドは最新版である 2.1.4 が使われることを確認しているから。

しかし,この状態で以下のスクリプトを動かすとどうなるか。

require "bundler"
Bundler.require

Ruby 2.6.5 では何事もなく終わるが,Ruby 2.7.0 ではドバドバっとメッセージが出る。
先頭はこれ。

Warning: the running version of Bundler (2.1.2) is older than the version that created the lockfile (2.1.4). We suggest you to upgrade to the version that created the lockfile by running `gem install bundler:2.1.4`.

これはエラーではなく警告。
「Gemfile.lock に書いとる(Bundler の)バージョンは 2.1.4 なのに,今走っとる Bundler は 2.1.2。古いやんけ」
と怒っているようだ。

親切にも
gem install bundler:2.1.4 ってやってアップグレードしたらよろし」
て suggest してくれてるのだが,もう入っとるっちゅーに。

末尾はこれ。

/Users/hogehoge/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems.rb:275:in `find_spec_for_exe': Could not find 'bundler' (2.1.4) required by your /Users/hogehoge/temp/xxx/Gemfile.lock. (Gem::GemNotFoundException)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.1.4`

こっちは警告じゃなくてエラー。
「Gemfile.lock で要求されている bundler 2.1.4 が,み,見つからない」(がくっ)
という dying message を残して死亡している。

これはどう解釈できるのか?
実験 3 の結果と整合的,という気はする。
Ruby 2.7.0 では単純に bundler を require すると,なぜか最新版ではなく 2.1.2 が読み込まれるのだった。

実験 5

実験 4 と同じファイルを使い,

bundle exec ruby hoge.rb

のような形でスクリプトを動かすと正常だった。
bundle exec は,(よく分からんけど)Gemfile.lock の内容を見て使う gem のバージョンを決定してからスクリプトを動かすらしいので,これで正常化するのは納得できる気がする。

ruby コマンドでなく,Rake タスクを実行したいときは要注意。
いままで

rake hoge

とやっていたのを

bundle exec rake hoge

とするためには,Gemfile に gem 'rake' を入れてやらないといけない。

対策

結局どうすればいいのか。
おそらく以下の二つしかないと思う。

  • bundle exec を付けて実行
  • require "bundler" の前に gem "bundler" を書く

前者の場合,Rake タスクなら Gemfile を書き換える必要がある。確かめてはいないが Thor タスクでも同様だろう。
後者の場合も当然スクリプトを書き換える必要がある。

既存のコードを大量に書き換えなければならないことになりそう。
え〜っ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スクリプト言語の比較しながらGoのお勉強 〜 環境構築編(MacOS)

ごあいさつ

はじめまして。@kuroseetsと申します。
2000年からフリーランスで仕事を始め開発12年、インフラ8年経験してきたオッサンです。
皆さんはどのプログラミング言語、スクリプト言語が好きですか?または仕事などで何をよく使っていますか?
開発をされている方だとJavaが多いのかな?またはC#?Ruby?PHP?
事務系でスクリプトを組む方などはVBScriptなども現役ですよね。
私は現在インフラ運用構築側にいますので、私を含めて周辺でよく使われているのが、Python, Ruby, Perl, Bash辺りが多く、最近ではさらにGolangが増えてきている印象です。(あくまで個人的主観で、ですよ
それぞれ好みはあるとは思いますが、環境や現場による制約で使えるもの使えないものがありまして、私もその都度現場でキャッチアップしてスキルを身に付けてきました。
現在ではInfrastructure as Codeと謳われるだけあって、構成管理の設定ファイル以外でも手を動かすことも増えてきたと身を以て感じています。
今回個人的にGolangを勉強しようと思っているのですが、折角なので勉強ついでに有名なスクリプト言語を比較してみようかなと思います。
対象はGolangの他、Python, Ruby, Perl, Bash(インフラ運用4強スクリプト!)を予定しています。


環境構築

使うからには最新版を使いたい!
ということで常に最新版をインストールしやすく、また管理しやすくするためにバージョン管理ツール越しにインタプリタをインストールすることにしました。

anyenvのインストール

@rinpa さんの https://qiita.com/rinpa/items/81766cd6a7b23dea9f3c を参考にしてインストールしました。
各スクリプト言語を使用するのにenv系コマンドは非常に便利なのですが、個別にインストールすると面倒です。
が、anyenvで一元管理できたら非常に便利ですね。

# anyenvインストール
brew install anyenv

# anyenvが実行できるか確認
anyenv --version

# 初期ディレクトリがないので初期化して作成
anyenv install --init

# インストールできるenv系コマンドの確認
anyenv install -l

# 各envをインストール
anyenv install goenv
anyenv install pyenv
anyenv install rbenv
anyenv install plenv

# 環境変数の設定
echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

golang

golangの最新版のインストールはgoenvに従って粛々と進めていきます。

# インストール可能なgoのバージョンを確認
goenv install -l

# 最新版をインストール(執筆時は1.13.6)
goenv install 1.13.6

# インストールしたバージョンを指定
goenv global 1.13.6

# 指定したバージョンが実行できているか確認
go --version

python

pythonも同様に最新版をインストールします。

# インストール可能なpythonのバージョンを確認
pyenv install -l

# 最新版をインストール(執筆時は3.8.1)
pyenv install 3.8.1

# インストールした最新版バージョンを指定
pyenv global 3.8.1

# 指定したバージョンが実行できているか確認
python --version

ruby

rubyも同じ手順です。

# インストール可能なrubyのバージョンを確認
rbenv install -l

# 最新版をインストール(執筆時は2.7.0)
rbenv install 2.7.0

# インストールした最新版バージョンを指定
rbenv global 2.7.0

# 指定したバージョンが実行できているか確認
ruby --version

perl

そしてperlも。

# インストール可能なrubyのバージョンを確認
plenv install -l

# stableの最新版をインストール(執筆時は5.30.1)
plenv install 5.30.1

# インストールした最新版バージョンを指定
plenv global 5.30.1

# 指定したバージョンが実行できているか確認
perl --version

bash

anyenvにはbashのバージョンを管理するツールがありませんので、下記のツールを利用させて頂きました。
https://i-beam.org/2015/12/25/211817/

サイトを参考にインストールしてみましたがエラーが出ました

git clone https://github.com/ueokande/bashvm ~/.bashvm
echo 'source $HOME/.bashvm/bin/bashvm-init' >> ~/.bashrc
source ~/.bashrc

  readlink: illegal option -- f
  usage: readlink [-n] [file ...]

BSD系のMacはreadlink-fオプションがないみたいですね
こちらを参考にreadlink -fするコマンドを作成
https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac

cat << 'EOF' > /usr/local/bin/readlinkf
#!/bin/sh

TARGET_FILE=$1

cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`

# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
    TARGET_FILE=`readlink $TARGET_FILE`
    cd `dirname $TARGET_FILE`
    TARGET_FILE=`basename $TARGET_FILE`
done

# Compute the canonicalized name by finding the physical path 
# for the directory we're in and appending the target file.
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
echo $RESULT
EOF
chmod 755 /usr/local/bin/readlinkf

readlink -fしているところをこのコマンドに置き換えます

--- bashvm-init.bak 2020-01-18 07:08:43.000000000 +0900
+++ bashvm-init 2020-01-18 07:09:30.000000000 +0900
@@ -124,7 +124,7 @@
 export -f bashvm

 export BASHVM_HOME=${BASHVM_HOME:-$HOME/.bashvm}
-PATH="$(readlink -f $(dirname $BASH_SOURCE)):$PATH"
+PATH="$(readlinkf $(dirname $BASH_SOURCE)):$PATH"

 test -f $BASHVM_HOME/config && source $BASHVM_HOME/config
 export bashvm_default_version=${bashvm_default_version:-system}

改めてsource ~/.bashrcを実行すると成功しました
ではbashの最新版をインストールします

# 執筆次の最新は5.0
bashvm install 5.0

# インストールした最新版バージョンを指定
bashvm use 5.0

# 指定したバージョンが実行できているか確認
bash --version

以上で構築作業は完了です。
次回から各言語を比較しながらプログラミングしていきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails Tutorial 第一章でつまづいたところと参考URL(簡易メモ)

○所要時間
とりあえず一読 → 2:30(現在合計2:30)
一読後手を動かして → 4:00(現在合計4:00)
合計6:30

・cloud9初期設定迷う
→初期設定から変更なしでOK
参考URL:https://note.com/yutsuku/n/ncb752afcc61f

・rails server 起動できない(rails serverが弾かれる)
javascriptをダウンロード(具体的には、vi Gemfile→最後に「gem 'therubyracer'」を追記)
参考URL:http://yso15.hatenablog.com/entry/2015/03/21/225843

かつ、cd ~/environment/hello_app でディレクトリ の移動後、rails serverを起動。

・rais serverってどうやって開けば(確認すれば)いいの?
ページの表示方法は以下
0.画面上部tools→preview(これ以外下記参考URL引用)
1. $ rails serverでサーバを起動する(上記の結果でOK)
2. 画面上部Preview → Preview Running Application をクリック
3. cloud9上にブラウザが表示されるので、アドレスバーの右にあるボタンをクリック
4. ページが表示される。
参考URL:https://qiita.com/iwato/items/c70eeb87f944043ba356

・Gitでユーザを確認する方法
git config --global --list
Gitユーザを切り替える方法
XXXXのところは自分のユーザ名とメールアドレスに置き換えてください。
git config --global user.name XXXXX
git config --global user.email xxxx@xxxx.xxx
参考URL:http://javatechnology.net/service/git-config-global-list-user/

・git公開鍵のbitbucketへの登録
1.公開鍵が作成されているか確認する
$ cat ~/.ssh/id_rsa.pub
2.公開鍵を作成する
$ cd ~/.ssh
$ ssh-keygen
(ssh-keygenでAWS上の/var/lib/jenkins/.sshに公開鍵、秘密鍵を作るでした。)
参考URL:https://teratail.com/questions/48406

→ssh key imageなるもの(The key's randomart image)ができてこれは使えなかった→cat id_rsa.pubで確認すると、ssh-rsaで始まるものが出てきて、これはbitbucketでsshkeyとして使えた。
参考URL:https://note.com/yutsuku/n/ncb752afcc61f

・bitbucket登録後、Bitbucketへのリポジトリ追加とリポジトリへのプッシュ
$ cd ~/environment/hello_app(この移動大事)(要はhello_appのマスターブランチで以下コマンドを行うということ)
$ git remote add origin git@bitbucket.org:アカウント名/hello_app.git
$ git push -u origin master
参考URL:https://note.com/yutsuku/n/ncb752afcc61f

・$ bundle install --without production
→"Gemfile could no locate"のエラー
→hello_app(master)に移動して実行

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのコロン:の位置がわかるようになる記事

RubyやRailsを書いていると:が前に来たり、後ろついたりとてもややこしくありませんか??
というわけで:を前に書く時と後ろに書くときのパターンについて、整理していきたいと思います。

後置:パターン。


test.rb
#ハッシュのキーをシンボルとして定義
hash  = { a: 1, b: 2, c: 3 }

#キーワード引数(シンボルとは異なる)を利用するパターン
def my_method(arg1: arg:2)         
  pp arg1, arg2
end

以上の2パターンが後置:です。

では前置:のパターンをみていきましょう。

前置:パターン

test.rb
#その他はすべて後置:です。
hash[:a] = 4      

なんと上記の2つ以外はすべて後置:です。

こうやって整理してみると意外とシンプルなものですね〜

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby 2.7.0 + Rails 5.2.4 + mysql 5.7.28 でDocker開発環境を構築する備忘録

流れ

  1. Dockerfileを作成
  2. docker-compose.ymlを作成
  3. Gemfile,Gemfile.lockを作成
  4. イメージ・コンテナの作成
  5. Rails初期設定
  6. Githubにリモートリポジトリ作成

ディレクトリ構成

application_root/
 - Dockerfile
 - docker-compose.yml
 - Gemfile
 - Gemfile.lock
 - その他Railsアプリケーションファイル群

Dockerfileを作成

application_root下に下記のファイルを作成

# イメージのベースラインにRuby2.7.0を指定
FROM ruby:2.7.0
# Railsに必要なパッケージをインストール
RUN apt-get update -qq && apt-get install -y build-essential nodejs
RUN gem install bundler
# ルートディレクトリを作成
RUN mkdir /app
# 作業ディレクトリを指定
WORKDIR /app
# ローカルのGemfileとGemfile.lockをコピー
COPY ./Gemfile /app/Gemfile
COPY ./Gemfile.lock /app/Gemfile.lock
# Gemのインストール実行
RUN bundle install
# カレントディレクトリの内容をコピー
COPY . .

docker-compose.ymlを作成

同様に下記のファイルを作成。
DBはmysqlで、ローカルにデータストアを設けて永続化している。

# docker-compose.ymlフォーマットのバージョン指定
version: '3'
services:
  # Railsコンテナ定義
  web:
    # Dockerfileを使用してイメージをビルド
    build: .
    # ポート3000が来たらrailsサーバーが応答
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    # ローカルのsrcをコンテナにマウント
    volumes:
      - .:/app
    ports:
      - 3000:3000
    # dbコンテナが先に起動するよう設定
    depends_on:
      - mysql
    tty: true
    stdin_open: true
  # MySQLコンテナ定義
  mysql:
    # mysqlを使用してコンテナ作成
    image: mysql:5.7.28
    volumes:
      # データストアからマウント
      - ./tmp/mysql:/var/lib/mysql
    # コンテナ内の環境変数を定義
    environment:
      # mysqlのルートユーザーのパスワード設定
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"
    restart: always

Gemfile,Gemfile.lockの作成

以下のコマンドでGemfileを作成。

bundle init

下記のように編集。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails", "~> 5.2.4"

Gemfile.lockは空で作成しておく。

touch Gemfile.lock

イメージ・コンテナの作成

Railsプロジェクトを作成する。

docker-compose run web rails new . --force --database=mysql

Dockerイメージを作成する。(で合っているよね?)

docker-compose build

作成されたイメージを確認できる。
コンテナはまだない。

# イメージのリスト
docker image list

# 動作しているコンテナ一覧
docker ps

ここまでがうまくいかなかった時は削除してやり直す。

docker rm -f [container_id]
docker rmi -f [image_id]

いよいよコンテナを立ち上げる。
-dをつけるとデーモン実行できるが、ログを見たいのでそのまま実行。

docker-compose up

Rails初期設定

config/database.ymlのpassword, hostを編集する。

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # docker-compose.ymlに記載したパスワード
  host: mysql # docker-compose.ymlに記載したホスト名

コンテナ内に入って、DBを作成する。

docker exec -it [container_name] bash
rake db:create

下記URLで動作が確認できる。
http://localhost:3000

スクリーンショット 2020-01-18 0.33.27.png

Github設定(ついでに)

Githubアカウントは作ってある前提で・・・

まずはSSHキーを作成。もうある場合は不要。
内容をGithubの設定から、SSH keysにアップロードする。

ssh-keygen -t rsa
cat .ssh/id_rsa.pub

あとはリモートリポジトリのSSHアドレスを設定してPush。

# ユーザー名の設定
git config --global user.name [ユーザー名]

# リモートリポジトリの設定
git remote add origin git@github.com:xxxxxxxx/xxxxxxxxx.git

# アプリケーションの初期状態をPush
git add -A
git commit -m "create application"
git push origin master
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む