Study & Practice

北海道札幌市のプログラマによる技術とか雑記のブログ

MacにHomebrewをインストールする方法

M1 MacBook Airを購入して本日無事届いたので開発環境構築のためにまずHomebrewをインストールした

Homebrewのインストール方法だが

まずHomebrewのページにアクセスしてページ上部にあるインストール用のコマンドをコピーしてターミナルで実行する

コマンドは2021年1月21日現在で以下のようになっている

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

パスワードが要求されるのでMacのログイン時のパスワードを入力する

そうするとインストールが実行される。正常に終了すると「Installation successful!」と出力される

最後にPathの設定をする。
※少し前までは必要なかったのか「Homebew インストール」とGoogle検索して出てくるページにはPathの設定が必要という記事は見当たらなかった。もしかしたら環境によっては不要なのかもしれない。

おそらく「Installation successful!」の少し下に以下のような出力があると思う

==> Next steps:
- Add Homebrew to your PATH in /Users/carametal/.zprofile:
    echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> /Users/carametal/.zprofile
    eval $(/opt/homebrew/bin/brew shellenv)
- Run `brew help` to get started
- Further documentation: 
    https://docs.brew.sh

これは私の場合なので出力は人によって違うと思うが、上記の出力の2行目と3行目のコマンド(echoとeval)を実行するとPathが設定される。

以上の手順が終わればインストールが正常に完了しているはず。以下のコマンドでバージョンが正常に動くかどうかを確認して終了

brew -v

執筆時点での出力は以下

Homebrew 2.7.5
Homebrew/homebrew-core (git revision aac1e; last commit 2021-01-21)

CodeDeployを使ってEC2インスタンスにLaravelプロジェクトをデプロイする

AWSを有効活用するためCI/CD系をとりあえず試している中でCodeDeployの使い方は少しずつ分かってきたので、手順をまとめる。

EC2インスタンスの起動

まずはデプロイするサーバーとしてEC2インスタンスを起動します。
AWSマネジメントコンソールを開き、こちらの記事の「EC2インスタンスの作成」までを行ってください。

carametal.hatenablog.com

ただ、注意点としてステップ 3: インスタンスの詳細の設定で「AmazonEC2RoleforAWSCodeDeploy」ポリシーをもったIAMロールを設定するようにしてください。
なお、本記事ではEC2にKey=Name,Value=CodeDeployTrialというタグをつけたと仮定して進めていきます。

CodeDeployエージェントのインストール

次にCodeDeployを実行に必要なパッケージをEC2インスタンスにインストールします。

sshでEC2インスタンスに入ったら以下のコマンドを実行します。

sudo yum update -y
sudo yum -y install ruby
sudo yum install -y wget
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto

5つ目のwgetコマンドに渡しているURLはEC2がどのリージョンにあるかによって変わります。
詳しくは以下をご覧ください。
CodeDeploy リソースキットリファレンス - AWS CodeDeploy

以上のコマンドが正常に終了したらCodeDeployエージェントのインストールは完了です。

Laravelプロジェクトの作成

ローカルの開発マシンにlaravel newコマンドでLaravelプロジェクトを作成します。Composerを使いますのでもしインストールをされていない方は以下からダウンロードしてください。
https://getcomposer.org/download/

以下のコマンドを実行するとcode-deploy-tiralというディレクトリを作成されます。その中にLaravelに必要なパッケージが揃った状態になっています。

laravel new code-deploy-trial

CodeDeployに必要なファイルを作成

code-deploy-trialディレクトリに入ります。

cd code-deploy-trial

以下の構成になるようにファイル、ディレクトリを作ります。

scripts
└ install_dependencies.sh
└ start_server.sh
└ stop_server.sh
appspec.yml

code-deploy-trialディレクトリ直下にappspec.ymlとscriptsディレクトリ、scriptsディレクトリに.shファイルが3つです。

そして各ファイルは以下の内容になります。

appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: root

install_dependencies.sh

#!/bin/bash
yum install -y httpd
amazon-linux-extras install php7.3


start_server.sh

#!/bin/bash
systemctl start httpd.service

stop_server.sh

#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  $isExistApp ]]; then
	systemctl stop httpd
fi

install_dependencies.shのyum installは-yオプションを付け忘れると後々デプロイを失敗することがあります。注意してください。

これで設定ファイルの準備ができました。

ソースコードをデプロイするためのS3バケットの準備

s3バケットを作ります。
code-deploy-trialというバケット名は既に使われていたのでcarametal-code-deploy-trialとしました。

aws s3 mb s3://carametal-code-deploy-trial

S3バケットにCodeDeploy用のポリシーを設定します。

bucket-policy.jsonというファイルを以下の内容で作成してください。
バケット名、使用しているIAMユーザーのID、EC2を作るときに設定したIAMロールのARNとなっている部分は皆さんの環境に合わせて入れ替えてください。

{
  "Statement": [
      {
          "Action": [
              "s3:PutObject"
          ],
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::バケット名/*",
          "Principal": {
              "AWS": [
                  "使用しているIAMユーザーのID"
              ]
          }
      },
      {
        "Action": [
            "s3:Get*",
            "s3:List*"
        ],
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::バケット名/*",
        "Principal": {
            "AWS": [
                "EC2を作るときに設定したIAMロールのARN"
            ]
        }
    }
  ]
}

ちなみに使用しているIAMユーザーのIDは以下のコマンドでとれます。ちなみにIAMユーザーのARNを設定しても問題ありません。

aws sts get-caller-identity

EC2を作るときに設定したIAMロールのARNは以下のコマンドで取れます。

 aws iam get-role --role-name CodeDeployTrialRole

bucket-policy.jsonの準備ができたらS3バケットにポリシーを紐づけします。

aws s3api put-bucket-policy --bucket carametal-code-deploy-trial --policy file://bucket-policy.json

これでS3バケットの準備は完了です。

CodeDeployのセットアップ

CodeDeployにデプロイするため必要な準備を行っていきます。

まずはCodeDeployで扱うアプリケーションを作成します。
今回はCodeDeployTrialという名前でアプリケーションを作成します。

aws deploy create-application --application-name CodeDeployTrial

デプロイグループを作成します。
「EC2に設定したNameタグの値」と「AWSCodeDeployRoleを持つIAMロールのARN」はみなさんの環境に応じて変更してください。

aws deploy create-deployment-group --application-name CodeDeployTrial \
  --deployment-group-name CodeDeployTrialGroup \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --ec2-tag-filters Key=Name,Value=EC2に設定したNameタグの値,Type=KEY_AND_VALUE \
  --service-role-arn AWSCodeDeployRoleを持つIAMロールのARN

アプリケーションのデプロイ

そしていよいよアプリ―ケーションのデプロイを行います。
まずはソースコードをS3にアップロードします。

aws deploy push \
  --application-name CodeDeployTrial \
  --s3-location s3://carametal-code-deploy-trial/code-deploy-trial.zip

※以下のコマンドを実行するとLaravelプロジェクトのすべてのファイルがs3にアップロードされます。本来.envファイルやvendorディレクトリなどはサーバーごとで別のものを用意するべきと言われています。注意してください

そしてEC2インスタンスへのデプロイです。

aws deploy create-deployment \
  --application-name CodeDeployTrial\
  --deployment-group-name CodeDeployTrialGroup \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --s3-location bucket=carametal-code-deploy-trial,bundleType=zip,key=code-deploy-trial.zip,eTag=s3オブジェクトのETag

s3オブジェクトのETagとなっている部分は以下のコマンドで取得できます。

    • bucketバケット名、--keyは取得したいファイルのパスを引数とします。
aws s3api head-object --bucket carametal-code-deploy-trial --key code-deploy-trial.zip

これでデプロイの完了です。ただまだ終わりません。

Apacheの設定をLaravel向けにする

この状態でEC2インスタンスIPアドレスにアクセスしてみてもApacheのテストページが表示されてしまいます。設定ファイルの内容を変更してLaravelに向けるようにします。
/etc/httpd/conf/httpd.confをテキストエディタで開いて編集します。

sudo vim /etc/httpd/conf/httpd.conf

DocumentRootを"/var/www/html"から"/var/www/html/public"に変更します。

# DocumentRoot "/var/www/html"
DocumentRoot "/var/www/html/public"

これでIPへのアクセスがLaravelに向きます。

それともう一つの中にあるAllowOverrideをNoneからAllに変更します。
コメントがたくさんあると思いますが、コメントを除くと以下のようになります。
これはドキュメントルート以外にアクセスするために必要な設定です。

<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    # AllowOverride None
    AllowOverride All
    Require all granted
</Directory>

このままだとLogが書き込めなかったというエラーになるので以下を実行します。
/var/www/html配下のディレクトリとファイルがapacheの所有物になりLogへの書き込みが可能になります。

sudo chown -R apache:apache /var/www/html/*

ようやくEC2のIPアドレスへブラウザからアクセスするとLaravelのwelcomページが表示されます。

これでLaravelプロジェクトをEC2インスタンスにデプロイできました。が、もう少しだけ続きます。

再デプロイ

先ほどAllowOverrideを変更してドキュメントルート以外へのアクセスを有効にしましたが、まだ実際に動くコードがありません。
なのでコードを追加し、EC2インスタンスに再デプロイして確かめてみます。
Laravelプロジェクトのroutes/web.phpの末尾に以下を追加します。

Route::get('info', function() {
    phpinfo();
});

S3へのaws deploy pushとaws deploy create-deploymentを再度実行します。create-deploymentのeTagはpushするたびに更新されるので新しい値を入力してください。

これでIPアドレス/infoにブラウザからアクセスするとPHPの詳細情報が表示されるはずです。

まとめ

なんとかCodeDeployの初歩的な使い方は理解できたかなと思います。ただ、.envとかvendorとかもまとめてデプロイしちゃってるから実際に運用するには向いてない。もっというとCI/CDにはまだほど遠いので、次回はCodePipelineも使ってより実践的な手法を身に着けたい。

AWS CLIでS3バケットを作ろうとしたら「The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.」を言われた時の対処法

CodeDeployのためにS3バケットを作るために

aws s3api create-bucket --bucket バケット名

というコマンドを実行すると

An error occurred (IllegalLocationConstraintException) when calling the CreateBucket operation: The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.

というエラーが返ってきた。

リージョンが指定されていないという内容のようなので以下のようにリージョンを指定してコマンドを実行したが同じエラーが出てきた。

aws s3api create-bucket --bucket バケット名 --region ap-northeast-1

公式ドキュメントのExamplesにも

aws s3api create-bucket --bucket my-bucket --region us-east-1

というコマンドが記載されているが動かなかった

と思ったらもう少し下にus-east-1以外のリージョンを使いたいならLocationConstraintっていうのを使えと書いてあった

LocationConstraintは--create-bucket-configurationというオプションで指定する項目でリージョンにap-northeast-1を指定する場合は以下のような使い方になる

aws s3api create-bucket --bucket バケット名 --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1

ちなみにこのコマンドだとリージョン2回指定してるじゃんと思って以下のようなコマンドを実行してみたところ正常にバケットが作られた。--regionオプションは使わなくても大丈夫みたい

aws s3api create-bucket --bucket バケット名 --create-bucket-configuration LocationConstraint=ap-northeast-1

ただ公式ドキュメントには--regionもLocationConstraintも両方指定するコマンドが載ってるしどっかで不具合が起きるかもしれないのでちゃんと両方指定しておくのが安全かなと思います。

一時的にAWSのProfileを切り替える方法

carametalというprofile名を指定したい場合

Linux,Macの場合

export AWS_PROFILE=carametal

Windowの場合

set AWS_PROFILE=carametal

これでターミナルから出るとデフォルトに戻る状態でProfileを切り替えることができる

WSLで使用する既定のディストリビューションを切り替える方法

コマンドプロンプトからwslコマンドで入れるLinuxディストリビューションを切り替えたいときに使える方法です。

打つのが面倒でなければ

wsl -d Ubuntu-18.04

のように

wsl -d ディストリビューション名

ディストリビューションを指定することができます。

既定に設定したい場合は

wsl -s Ubuntu-18.04

のように-sオプションを付けることで既定のディストリビューションに設定することができます。

Laravelのクエリビルダ基礎(SELECT編)

はじめに

Laravelでクエリビルダを使ったクエリを実行するコードを書くたびにドキュメントを見ていたので覚えるためにもいったん基本的な使い方をまとめて書いてみることにしました。

今回の内容はすべて
readouble.com
に含まれています。

テーブルはLaravelのデフォルトの認証機能を使用したときのusersテーブルをベースに以下のようなテーブルを想定しています。

カラム名 データ型
id bigint(20) unsigned
name varchar(20)
email varchar(20)

本記事で利用するコードはすべてIlluminate\Support\Facades\DBクラスを使用するため、以下のようにインポート文を追加する必要があります。

use Illuminate\Support\Facades\DB;

クエリビルダの使い方

まずは基本的なSELECTからです

$users = DB::table('users')->get();

このコードは

select * from users;

と同等のクエリが実行されます。これにWhere句を追加したい場合は

$users = DB::table('users')->where('name', '=', 'carametal')->get();

となります。ただ、where句のオペレーターが上記のように「=」の場合は第2引数を省略することができ

$users = DB::table('users')->where('name', 'carametal')->get();

でも同様に動作します。

Where句をid(primary key)で絞る場合は以下のようにfindメソッドが使えます

$user = DB::table('users')->find(1);

getメソッドは結果が1レコードであっても配列を取得するのに対してfindメソッドはオブジェクトを1つだけ取得します。

primary key以外でレコードを絞り込みたいがfindメソッドのようにオブジェクト1つだけを取得したい場合はfirstメソッドを使うことができます

$users = DB::table('users')->where('name', 'carametal')->first();

もしfirstメソッドを使用したのにSQLの結果が複数行あった場合は内部的に一番最初に見つかったレコードのみを返します。今回のテーブルでいうとidが小さいレコードが優先されます。

where句で条件を複数指定したい場合は配列で条件を渡すこともできます。

$users = DB::table('users')->where([['id', 1], ['name', 'carametal']])->get();

where句を複数していすることもできます。

$users = DB::table('users')->where('id', 1)->where('name', 'carametal')->get();

条件指定にorを使いたい場合はorWhereメソッドが用意されています

$users = DB::table('users')->where('id', 1)->orWhere('name', 'carametal')->get();

またSQLの結果を集計したい場合にはcountメソッドやmaxメソッドを使うこともできます。

$count = DB::table('users')->count();

join句はメソッドで用意されています

$user = DB::table('users')->join('contacts', 'user.id', '=', 'contacts.user_id')->select('users.*', 'contacs.phone')->get();

join句もwhere句と同様にオペレータを省略することができます。

$user = DB::table('users')->join('contacts', 'user.id', 'contacts.user_id')->select('users.*', 'contacs.phone')->get();

joinメソッドはinner join、left outer joinはleftJoinメソッド、right outer joinはrightJoinメソッドがそれぞれ用意されているので必要に応じて使い分けることができます。

orderBy句もメソッドで用意されています。

$users = DB::table('users')->orderBy('id', 'desc')->get();

第一引数にカラム名、第二引数に昇順か降順かを指定します。第二引数は省略可能で省略した場合は昇順(asc)になります

またtimestampを採用している場合はlatestメソッド()、oldestメソッドを使ってcreated_atの順にソートすることもできます。

$users = DB::table('users')->latest()->get();

これで基礎的なSELECT実行するクエリビルダの使い方はまとまったかと思います。

このほかにもサブクエリなど応用的なメソッドもたくさんあるので、もっと深めたい方は是非公式ドキュメントをご覧ください。
readouble.com

Laravelのroute関数にパラメータを渡したいとき

例えばweb.phpに以下のようなrouteを設定した場合

Route::get('/hello-world', function () {
    return 'Hello,World.;
})->name('hello-world');

Laravel内で「/hello-world」というURLにhelloWorldという名前が付けられ

route('hello-world');

という書き方で「/hello-world」のURLが取得できるようになる

この場合でURLパラメータを加えた場合、つまり

Route::get('/hello-world/{name}', function ($name) {
    return "Hello,$name.";
})->name('hello-world');

のようにrouteを設定した場合、routeの呼び出しが側では以下のような書き方になる

route('/hello-world', ['name' => 'carametal']);

route関数の第2引数に連想配列を設定することでurlにパラメータを含めることができる