0. はじめに
大阪のLaravel初学者サウナーこと、kazumakishimoto(@kazuma_dev)です!
CircleCI / CodeDeploy
の自動デプロイ方法です。
0-1. 前回記事
- 【AWS】LaravelアプリをEC2デプロイ【まとめ編】
- 【AWS】LaravelアプリをEC2デプロイ①【CloudFormation / EC2 / RDS編】
- 【AWS】LaravelアプリをEC2デプロイ②【Route53編】
- 【AWS】LaravelアプリをEC2デプロイ③【ACM / ELB編】
0-2. 全体の流れ
0-3. 本記事の対象者
-
CircleCI / CodeDeploy
で自動デプロイしたい方
0-4. 事前準備
- AWSアカウント作成済み
- CircleCIアカウント作成済み
- リージョンはアジアパシフィック(東京)ap-northeast-1
-
grfl
やhoge
はサンプル名なので適宜変更して下さい
0-5. 要件
-
CircleCI
で自動デプロイ -
CodeDeploy
で自動デプロイ
0-6. 本番環境
ツール | バージョン |
---|---|
OS | Amazon Linux 2 |
nginx | 1.12 |
PHP | 7.4.28 |
Laravel | 6.20.44 |
MySQL | 5.7.37 |
Composer | 1.10.26 |
Node.js | 13.14.0 |
0-7. AWS構成図
1. CircleCI
1-1. 秘密鍵と公開鍵の作成
ec2-user
$ ssh ec2-user@xx.xxx.xxx.xxx -i ~/.ssh/hoge.pem
$ ssh-keygen -m pem -C ""
Enter×2
1-2. 公開鍵をGitHubへ登録
-
id_rsa.pub
の内容を貼り付け
ec2-user
$ cat ~/.ssh/id_rsa.pub
ec2-user
$ ssh git@github.com
PTY allocation request failed on channel 0
Hi あなたのGitHubアカウント名/grfl! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
1-3. 秘密鍵をCircleCIへ登録
-
id_rsa
の内容を貼り付け
ec2-user
$ cat ~/.ssh/id_rsa
1-4. 公開鍵認証
ec2-user
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
1-5. 環境変数
1-6. config.yml
grfl/.circleci/config.yml
version: 2.1
executors:
laravel-circleci:
docker:
- image: circleci/php:7.4-node-browsers
- image: circleci/mysql:5.7
environment:
- APP_DEBUG: true
- APP_ENV: testing
- APP_KEY: base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
- DB_CONNECTION: circle_testing
- MYSQL_ALLOW_EMPTY_PASSWORD: true
working_directory: ~/repo
commands:
install-dockerize:
steps:
- run:
name: Install dockerize
command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
environment:
DOCKERIZE_VERSION: v0.6.1
install-php-extensions:
steps:
- run:
name: Install PHP Exetensions
command: sudo docker-php-ext-install pdo_mysql
working_directory: src
restore-cache-composer:
steps:
- restore_cache:
key: v1-dependencies-{{ checksum "src/composer.json" }}
install-composer:
steps:
- run:
name: Install Composer
command: composer install -n --prefer-dist
working_directory: src
save-cache-composer:
steps:
- save_cache:
key: v1-dependencies-{{ checksum "src/composer.json" }}
paths:
- vendor
npm-ci:
steps:
- run:
name: npm CI
command: |
if [ ! -d node_modules ]; then
npm ci
fi
working_directory: src
restore-cache-npm:
steps:
- restore_cache:
key: npm-cache-{{ checksum "src/package-lock.json" }}
npm-run-dev:
steps:
- run:
name: Run npm
command: npm run dev
working_directory: src
save-cache-npm:
steps:
- save_cache:
key: npm-cache-{{ checksum "src/package-lock.json" }}
paths:
- node_modules
migration-seeding:
steps:
- run:
name: Migration & Seeding
command: php artisan migrate --seed
working_directory: src
test-unittest:
steps:
- run:
name: Run PHPUnit
command: vendor/bin/phpunit
working_directory: src
jobs:
build:
executor:
name: laravel-circleci
steps:
- checkout
- install-dockerize
- install-php-extensions
- restore-cache-composer
- install-composer
- save-cache-composer
- restore-cache-npm
- npm-ci
- save-cache-npm
- npm-run-dev
- migration-seeding
- test-unittest
deploy:
docker:
- image: circleci/php:7.4-node-browsers
steps:
- checkout
+ - add_ssh_keys
- run:
+ name: aws deploy
command: |
+ ssh -o StrictHostKeyChecking=no -t ec2-user@${HOST_NAME} "cd grfl && \
+ git pull origin master && \
+ cd /var/www/grfl/src && \
+ composer install -n --no-dev --prefer-dist && \
+ npm ci && \
+ npm run prod && \
+ php artisan migrate --force && \
+ php artisan config:cache"
workflows:
version: 2
build_deploy:
jobs:
- build
- deploy:
requires:
- build
filters:
branches:
only:
- master
1-7. 自動デプロイ(CircleCI)
- ローカルのmasterブランチに、リモートのmasterブランチの内容を反映しておく
- commit & push → deploy!
- 下記のようなエラーログがCircleCIで発生する場合、権限や所有権を確認してください
1-7-1. エラーログ
Warning: Permanently added '**************' (ECDSA) to the list of known hosts.
error: cannot open .git/FETCH_HEAD: Permission denied
error: unable to unlink old '.circleci/config.yml': Permission denied
npm WARN prepare removing existing node_modules/ before installation
[..................] / : WARN prepare removing existing node_modules/ before innpm ERR! code EACCES
npm ERR! syscall rmdir
npm ERR! path /var/www/****/src/node_modules/@ampproject
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, rmdir '/var/www/****/src/node_modules/@ampproject'
npm ERR! [OperationalError: EACCES: permission denied, rmdir '/var/www/****/src/node_modules/@ampproject'] {
npm ERR! cause: [Error: EACCES: permission denied, rmdir '/var/www/****/src/node_modules/@ampproject'] {
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'rmdir',
npm ERR! path: '/var/www/****/src/node_modules/@ampproject'
npm ERR! },
npm ERR! isOperational: true,
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'rmdir',
npm ERR! path: '/var/www/****/src/node_modules/@ampproject'
npm ERR! }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/****/.npm/_logs/2022-05-31T09_51_53_058Z-debug.log
1-7-2. 権限変更
ec2-user
$ cd /var/www/grfl
$ sudo chmod 777 .git
$ sudo chown -R ec2-user:ec2-user .git/
$ sudo chown -R ec2-user:ec2-user .circleci
$ cd /var/www/grfl/src
$ sudo chown -R ec2-user:ec2-user node_modules
2. CodeDeploy
2-1. S3バケット作成
2-2. IAMロール作成(CodeDeploy用)
2-3. CodeDeploy作成
2-4. IAMロール作成(EC2用)
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::grfl-codedeploy-ap-northeast-1-xxxxxxxxxxxx",
"arn:aws:s3:::grfl-codedeploy-ap-northeast-1-xxxxxxxxxxxx/*"
]
}
]
}
2-5. CodeDeployAgentインストール
ec2-user
$ ssh ec2-user@xx.xxx.xxx.xxx -i ~/.ssh/hoge.pem
$ sudo yum install ruby -y
$ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID xxxxx
$ sudo service codedeploy-agent restart
10〜20秒待機
[ec2-user@ip-xxx-xxx-xxx-xxx ~]$
2-6. IAMユーザー作成&環境変数(CircleCI用)
2-6-1. IAMユーザー作成
2-6-2. 環境変数
2-6-3. ポリシー作成
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::grfl-codedeploy-ap-northeast-1-xxxxxxxxxxxx/*"
}
]
}
2-7. appspec.yml
grfl/appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /var/www/grfl/src
permissions:
- object: /var/www/grfl/src
owner: grfl
group: grfl
hooks:
AfterInstall:
- location: ./scripts/after_install.sh
timeout: 60
runas: grfl
2-8. after_install.sh
grfl/scripts/after_install.sh
#!/bin/bash
set -eux
cd /var/www/grfl/src
php artisan migrate --force
php artisan config:cache
ec2-user
$ cd /var/www/grfl/src
$ chmod +x scripts/after_install.sh
$ ls -l scripts
-rwxr-xr-x 1 xxxx xxxx 67 May 4 18:22 after_install.sh
2-9. config.yml
.circleci/config.yml
version: 2.1
executors:
laravel-circleci:
docker:
- image: circleci/php:7.4-node-browsers
- image: circleci/mysql:5.7
environment:
- APP_DEBUG: true
- APP_ENV: testing
- APP_KEY: base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
- DB_CONNECTION: circle_testing
- MYSQL_ALLOW_EMPTY_PASSWORD: true
working_directory: ~/repo
commands:
install-dockerize:
steps:
- run:
name: Install dockerize
command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
environment:
DOCKERIZE_VERSION: v0.6.1
install-php-extensions:
steps:
- run:
name: Install PHP Exetensions
command: sudo docker-php-ext-install pdo_mysql
working_directory: src
restore-cache-composer:
steps:
- restore_cache:
key: v1-dependencies-{{ checksum "src/composer.json" }}
install-composer:
steps:
- run:
name: Install Composer
command: composer install -n --prefer-dist
working_directory: src
save-cache-composer:
steps:
- save_cache:
key: v1-dependencies-{{ checksum "src/composer.json" }}
paths:
- vendor
npm-ci:
steps:
- run:
name: npm CI
command: |
if [ ! -d node_modules ]; then
npm ci
fi
working_directory: src
restore-cache-npm:
steps:
- restore_cache:
key: npm-cache-{{ checksum "src/package-lock.json" }}
npm-run-dev:
steps:
- run:
name: Run npm
command: npm run dev
working_directory: src
save-cache-npm:
steps:
- save_cache:
key: npm-cache-{{ checksum "src/package-lock.json" }}
paths:
- node_modules
migration-seeding:
steps:
- run:
name: Migration & Seeding
command: php artisan migrate --seed
working_directory: src
test-unittest:
steps:
- run:
name: Run PHPUnit
command: vendor/bin/phpunit
working_directory: src
jobs:
build:
executor:
name: laravel-circleci
steps:
- checkout
- install-dockerize
- install-php-extensions
- restore-cache-composer
- install-composer
- save-cache-composer
- restore-cache-npm
- npm-ci
- save-cache-npm
- npm-run-dev
- migration-seeding
- test-unittest
deploy:
docker:
- image: circleci/php:7.4-node-browsers
environment:
AWS_DEFAULT_REGION: ap-northeast-1
steps:
- checkout
- run: sudo composer self-update --1
- restore_cache:
key: composer-no-dev-v1-{{ checksum "src/composer.lock" }}
- run:
command: composer install -n --no-dev --prefer-dist
working_directory: src
- save_cache:
key: composer-no-dev-v1-{{ checksum "src/composer.lock" }}
paths:
- vendor
- restore_cache:
key: npm-v1-{{ checksum "src/package-lock.json" }}
- run:
name: npm ci
command: |
if [ ! -d node_modules ]; then
npm ci
fi
working_directory: src
- save_cache:
key: npm-v1-{{ checksum "src/package-lock.json" }}
paths:
- node_modules
- run:
command: npm run prod
working_directory: src
- run:
name: archive artifacts
command: zip -ryq grfl.zip .
working_directory: src
- aws-cli/install
- run:
name: upload artifacts to s3
command: aws s3 cp grfl.zip s3://${AWS_S3_BUCKET_NAME}
working_directory: src
- run:
name: deploy to prod
command: |
aws deploy create-deployment \
--application-name grfl \
--deployment-group-name grfl \
--s3-location bucket=${AWS_S3_BUCKET_NAME},key=grfl.zip,bundleType=zip
working_directory: src
orbs:
aws-cli: circleci/aws-cli@1.0.0
workflows:
version: 2
build_deploy:
jobs:
- build
- deploy:
requires:
- build
filters:
branches:
only:
- master
2-10. EC2デプロイ先ディレクトリ退避
- 既にCodeDeploy以外の方法でデプロイされているディレクトリにCodeDeployでデプロイすると失敗するケースがあるため
ec2-user
$ ssh ec2-user@xx.xxx.xxx.xxx -i ~/.ssh/hoge.pem
$ cd /var/www
$ mv grfl grfl-ssh-deploy
$ mkdir grfl
$ cd /var/www/grfl
$ mkdir src
$ cd /var/www
$ cp grfl-ssh-deploy/src/.env grfl/src/.env
$ ls -l grfl/src
-rwxrwxr-x 1 ec2-user ec2-user 1913 Jun 1 08:33 .env
2-11. 自動デプロイ(CodeDeploy)
- ローカル開発ブランチでcommit & push
- GitHubでPR作成
- CircleCIの
build
ジョブが完了したら、PRをマージ
2-11-1. エラーログ
2-11-12. ヘルスチェック確認
2-11-3. S3バケット確認
2-12. 動作確認
ec2-user
$ cd /var/www/grfl/src
$ sudo chmod -R 777 storage
$ sudo chmod -R 777 bootstrap/cache
補足
開発環境(FW/ツールのバージョンなど)
ツール | バージョン |
---|---|
Vue.js | 2.6.14 |
jQuery | 3.4.1 |
PHP | 7.4.1 |
Laravel | 6.20.43 |
MySQL | 5.7.36 |
Nginx | 1.18.0 |
Composer | 2.0.14 |
npm | 6.14.6 |
Git | 2.33.1 |
Docker | 20.10.11 |
docker-compose | v2.2.1 |
PHPUnit | 8.0 |
CircleCI | 2.1 |
heroku | 7.59.4 |
MacBook Air | M1,2020 |
macOS | Monterey 12.3 |
Homebrew | 3.3.8 |
ディレクトリ構造
【ルートディレクトリ】
├─ .circleci
│ └─ config.yml
├─ aws / CloudFormation
│ └─ ec2.yml
├─ docker
│ └─ mysql
│ └─ nginx
│ └─ php
│ └─ phpmyadmin
├─ src
│ └─ 【Laravelのパッケージ】
└─ docker-compose.yml
Reference
次回記事
- 【AWS】LaravelアプリをEC2デプロイ⑤【SNS / Chatbot編】
- 【AWS】LaravelアプリをEC2デプロイ⑥【S3編】
- 【AWS】LaravelアプリをEC2デプロイ⑦【API編】
- 【AWS】お役立ちリンク集【随時更新】