EC2インスタンスの複製と再デプロイ

EC2インスタンスの複製方法と、その際に発生した問題と解決方法についてご紹介していきます！

##初めに
###何故EC2インスタンスを複製する必要があったのか？
・最初は問題なくEC2インスタンスにアプリをデプロイできたが、VPCのIPv4アドレスを/16で切ってしまっていたことで、その後サブネット作成時にIPv4アドレス選定の計算がめんどくさくなった。
→VPCのIPv4アドレスを/20で切って、サブネットを/24で切っておくと、後にサブネットを追加で作成する際にネットワークの切り分けが楽。

###何故サブネットのIPv4アドレスを/24で切っておくといいのか？
簡単にいうと、サブネットマスクを/20と/24で切った場合では、別サブネットを作成する際に選べるアドレスが以下のようになります。

・例　172.31.32.0/24
→末尾の0のみが可変できる数字になる。
　つまり、別のサブネットを作成する際、`172.31.32.0`の`32を33や34のように一つずらすだけ`でネットワークを切り分けることができるので計算が楽なんです！

・例　172.31.32.0/20
この場合は、選択範囲が172.31.32.0 - 172.31.47.255になります。
※計算はこちらのサイトで簡単にできます！
https://www.softel.co.jp/labs/tools/network/

と、このようにサブネットマスクを/24で切っておいた方が断然楽なので、IPv4aアドレスを割り当てし直そうということでEC2インスタンスを複製することにしました。

##EC2インスタンスの複製
では早速、既存のEC2インスタンスから新規インスタンスを作成していきます。
下記の参考記事の通りに進めればOKです。
※注意点として、新規でVPCとサブネットを作成する際、IPv4 CIDRをVPCは/20、サブネットは/24で切るようにしてください。

https://agohack.com/aws-duplicate-ec2-instance/

##ELPの関連付け
次に、下記の手順で既存EC2に関連付けしていたELPを解除して新規EC2に関連付けさせます。
`※ELPを解除しないまま既存EC2インスタンスを停止してしまうと課金が適用されてしまうので注意。`

1.既存EC2インスタンスとELPを解除し、インスタンス停止
下記記事に手順が記載されていますので参考にしてください。

https://qiita.com/r_saiki/items/6e8aefead1e2adebc43c

解除ができたら、既存EC2を停止してください。
![スクリーンショット 2022-01-09 12.12.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/f5df4e44-3940-547e-14f0-a8a08a02f299.png)

2.インターネットゲートウェイをアタッチ
このままELPを新規EC2に関連つけさせてもエラーになります。
理由は、現在のままだとインタネットゲートウェイがアタッチされているのは既存EC2で使用していたVPCだからです。
なので、現在のVPCをデタッチして新規で作成したVPCにアタッチしましょう！

![スクリーンショット 2022-01-09 13.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/e0a7317d-2c66-63cd-b678-2ab55ada433c.png)

アタッチできたらELPを新規EC2に関連付けさせてください。

##ssh接続の設定
このままだとターミナルからssh接続した時にエラーが出てしまいます。
なので、下記の設定をしていきます。

1.サブネットにルーティング追加
新規インスタンスのサブネット画面、「ルートテーブルの関連付けを編集」からインターネットゲートウェイへのルートを追加します。

![スクリーンショット 2022-01-09 14.11.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/9c48d9f0-9acf-06f9-d57d-a1625228abdf.png)

2.一旦ssh接続確認
試しにssh接続してみると下記のようにエラーが発生し、もう一つのコマンドだと接続できます。
このエラーは、同じFQDNで別のマシンに差し替わったので、なりすましかもしれないよ！という意味です。
known_hostsというファイルに残っている履歴を削除してあげることで、エラーが出たコマンドでも接続できるようになります。

```
.ssh $ ssh -i "???????-????.pem" ec2-user@ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:quupw3VFbI0PMBQiwz+w5qKL54RUDiBLO2ww+I5OYjA.
Please contact your system administrator.
Add correct host key in /Users/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /Users/.ssh/known_hosts:9
Host key for ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com has changed and you have requested strict checking.
Host key verification failed.
```

```
.ssh $ ssh -i "??????-????.pem" ec2-user@35.76.86.77
Last login: Mon Dec 20 07:10:40 2021 from p3014131-ipoe.ipoe.ocn.ne.jp

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-172-31-32-183 ~]$ 
```

3.known_hostsファイルの履歴削除
エラーを見ると、hostsの9行目が指摘されているので、known_hostsの中身を確認して下記コマンドで履歴を削除します。
※ここに関しては人によって違うかと思うので、ご自身の情報に当てはめて対処してください。

```
ssh-keygen -R ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com
```

これで再度ssh接続すると先ほどのコマンドで接続できることがわかります！


##アプリ起動
では早速、独自ドメイン、又はELPからアプリの起動確認をしてみましょう！

![スクリーンショット 2022-01-04 16.28.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/654a1c23-5202-3333-809e-1a90c4ec7160.png)

そうすると、あれ？404エラーが出ましたね。。。
404ということは、サーバーは問題なく動作しているので、OS側の設定が何処かおかしいのか？

ということで下記のように調査します。

1.curlコマンドでアクセス確認。
先ずは、ターミナルからssh接続し、curlで自分自身にアクセスしてみます。

```
ec2-user@ip-172-31-32-183 ~]$ curl 127.0.0.1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.20.0</center>
</body>
</html>
[ec2-user@ip-172-31-32-183 ~]$ 
```

404が返ってきましたね。

2.ログ確認
/log/php-fpm/error.logからログの確認をします。
エラーが吐かれてますね！

```
[root@ip-172-31-32-183 php-fpm]# tail error.log
[04-Jan-2022 15:12:41] WARNING: [pool www] ACL set, listen.owner = 'nginx' is ignored
[04-Jan-2022 15:12:41] WARNING: [pool www] ACL set, listen.group = 'nginx' is ignored
[04-Jan-2022 15:12:41] NOTICE: fpm is running, pid 26788
[04-Jan-2022 15:12:41] NOTICE: ready to handle connections
[04-Jan-2022 15:12:41] NOTICE: systemd monitor interval set to 10000ms
```

3.対処
`WARNING: [pool www] ACL set, listen.owner = 'nginx' is ignored`で検索してみて、記事を見つけたので参考に対処しましょう。

https://souiunogaii.hatenablog.com/entry/CentOS8-php-fpm-ACL#CentOS8%E3%81%AEOS%E5%86%8D%E8%B5%B7%E5%8B%95%E3%81%A7php-fpm%E3%81%8C%E5%86%8D%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BCACL-set-listenowner---is-ignoredACL-set-listengroup---is-ignored%E3%81%AE%E5%AF%BE%E5%87%A6%E6%89%8B%E9%A0%86

/etc/php-fpm.d/www.confの下記の箇所をコメントアウトします。

```
[root@ip-172-31-32-183 php-fpm.d]# vi /etc/php-fpm.d/www.conf

;listen.acl_users = apache,nginx #コメントアウト
```

編集を終えたら、php-fpmを再起動してphp-fpmを開き、先ほどのエラーが消えていれば成功です!

```
[root@ip-172-31-32-183 php-fpm.d]# systemctl restart php-fpm #再起動

[root@ip-172-31-32-183 php-fpm.d]# systemctl status php-fpm #起動状態確認
● php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2022-01-06 14:00:02 UTC; 7s ago
 Main PID: 8215 (php-fpm)
   Status: "Ready to handle connections"
   CGroup: /system.slice/php-fpm.service
           ├─8215 php-fpm: master process (/etc/php-fpm.conf)
           ├─8216 php-fpm: pool www
           ├─8217 php-fpm: pool www
           ├─8218 php-fpm: pool www
           ├─8219 php-fpm: pool www
           └─8220 php-fpm: pool www

Jan 06 14:00:02 ip-172-31-32-183.ap-northeast-1.compute.internal systemd[1]: Starting The...
Jan 06 14:00:02 ip-172-31-32-183.ap-northeast-1.compute.internal systemd[1]: Started The ...
Hint: Some lines were ellipsized, use -l to show in full.

[root@ip-172-31-32-183 php-fpm.d]# tail /var/log/php-fpm/error.log　#ログ確認
[04-Jan-2022 15:12:41] WARNING: [pool www] ACL set, listen.owner = 'nginx' is ignored
[04-Jan-2022 15:12:41] WARNING: [pool www] ACL set, listen.group = 'nginx' is ignored
[04-Jan-2022 15:12:41] NOTICE: fpm is running, pid 26788
[04-Jan-2022 15:12:41] NOTICE: ready to handle connections
[04-Jan-2022 15:12:41] NOTICE: systemd monitor interval set to 10000ms
[06-Jan-2022 14:00:01] NOTICE: Terminating ...
[06-Jan-2022 14:00:02] NOTICE: exiting, bye-bye!
[06-Jan-2022 14:00:02] NOTICE: fpm is running, pid 8215
[06-Jan-2022 14:00:02] NOTICE: ready to handle connections
[06-Jan-2022 14:00:02] NOTICE: systemd monitor interval set to 10000ms
```

おっと、まだエラーが出てますね。。。。

4.laravelのログ確認
一旦laravelの方のログを見てみます。

```
[root@ip-172-31-32-183 ~]# cd /var/www/laravel-zaikokanri/backend/storage/logs
[root@ip-172-31-32-183 logs]# ls
root@ip-172-31-32-183 logs]# 
```

あれ？あるはずのlaravel.logが無い？！

となると、恐らくLaravelのアプリ自体が正常に起動できていなく、ログが出力されてない状態のようです！

EC2の複製をオンラインのまま行ったとすると、もしかしたら変なセッションが残っていてそれが邪魔してる可能性があるので、一度OSを再起動してみます。

```
[root@ip-172-31-32-183 ~]# shutdown -r now #再起動
Connection to ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com closed by remote host.
Connection to ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com closed.

.ssh $ ssh -i "sample-key.pem" ec2-user@ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com　#接続タイムアウトで失敗
ssh: connect to host ec2-35-76-86-77.ap-northeast-1.compute.amazonaws.com port 22: Operation timed out

.ssh $ ssh -i "sample-key.pem" ec2-user@35.76.86.77 #接続
Last login: Fri Jan  7 10:11:02 2022 from p3014131-ipoe.ipoe.ocn.ne.jp

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
6 package(s) needed for security, out of 16 available
Run "sudo yum update" to apply all updates.

[ec2-user@ip-172-31-32-183 ~]$ curl 127.0.0.1 #アクセス確認
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.20.0</center>
</body>
</html>

[ec2-user@ip-172-31-32-183 ~]$ sudo su - #ルートユーザーに変更
最終ログイン: 2022/01/07 (金) 10:11:07 UTC日時 pts/0

[root@ip-172-31-32-183 ~]#  cd /var/www/laravel-zaikokanri/backend/storage/logs #logの場所まで移動

[root@ip-172-31-32-183 logs]# ls #laravel.logの確認
[root@ip-172-31-32-183 logs]#  #存在してない
```

再起動でもダメそうですね。。。

ここでメンターに相談。
キャッシュクリアやパーミッション、リンク等を一つずつ調査してもいいけど、laravelのプロジェクトを再デプロイしてしまった方が早いかもしれないとアドバイス頂きました！

ということで、laravelプロジェクトの再デプロイを進めていきます。
初めは、え？またインスタンスとか作り直すの？と思ったのですが、そんなことはする必要はなく、プロジェクトディレクトリを際クローンするだけなのでもう一踏ん張り頑張りましょう！

##再デプロイ

1.laravelプロジェクトをクローン
先ずは既存プロジェクトをコピー用で用意したディレクトリに移動させ、その後にgithubからプロジェクトをクローンしてきます。
※ここで既存プロジェクトは必要ないから削除しようとしてしまうところですが、新規でクローンしてきたプロジェクトのDB周りの設定を行う際に、既存プロジェクトのコードがみれた方が便利なので、既存プロジェクトは削除せず移動させるようにしましょう。

```
[root@ip-172-31-32-183 www]# mkdir copy-laravel-zaikokanri #既存プロジェクトの移動先を作成

[root@ip-172-31-32-183 www]# ls #作成されたか確認
cgi-bin  copy-laravel-zaikokanri  html  laravel-zaikokanri

[root@ip-172-31-32-183 www]# mv -v laravel-zaikokanri/ copy-laravel-zaikokanri/ #既存プロジェクトを移動 -vオプションで移動過程が表示されます。
‘laravel-zaikokanri/’ -> ‘copy-laravel-zaikokanri/laravel-zaikokanri’

[root@ip-172-31-32-183 www]# ls #ちゃんと移動できたか確認
cgi-bin  copy-laravel-zaikokanri  html
[root@ip-172-31-32-183 www]# cd copy-laravel-zaikokanri
[root@ip-172-31-32-183 copy-laravel-zaikokanri]# ls
laravel-zaikokanri

[root@ip-172-31-32-183 copy-laravel-zaikokanri]# cd ../ #プロジェクトクローン先に移動

[root@ip-172-31-32-183 www]# git clone https://github.com/?????/?????.git #githubからプロジェクトをクローン

Cloning into 'laravel-zaikokanri'...
remote: Enumerating objects: 2073, done.
remote: Counting objects: 100% (2073/2073), done.
remote: Compressing objects: 100% (773/773), done.
remote: Total 2073 (delta 1471), reused 1823 (delta 1259), pack-reused 0
Receiving objects: 100% (2073/2073), 963.78 KiB | 6.06 MiB/s, done.
Resolving deltas: 100% (1471/1471), done.
```

これでクローンが完了しました。
これだけではDB関係の設定ができてないのでアプリは起動できません。

2.DB設定

①.env作成
.env.exampleをコピーして.envを作成します。

```
[root@ip-172-31-32-183 backend]# cp .env.example .env 
```

②アプリケーションキーの作成
アプリケーションキーを作成しますが、このまま実行してもエラーになりますが、
composerをインストールすれば解決できます！

```
[root@ip-172-31-32-183 backend]# php artisan key:generate
PHP Warning:  require(/var/www/laravel-zaikokanri/backend/vendor/autoload.php): failed to open stream: No such file or directory in /var/www/laravel-zaikokanri/backend/artisan on line 18
PHP Fatal error:  require(): Failed opening required '/var/www/laravel-zaikokanri/backend/vendor/autoload.php' (include_path='.:/usr/share/pear:/usr/share/php') in /var/www/laravel-zaikokanri/backend/artisan on line 18

```

```
[root@ip-172-31-32-183 backend]# composer install
Package manifest generated successfully.
80 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

[root@ip-172-31-32-183 backend]# php artisan key:generate #キー作成
Application key set successfully.

[root@ip-172-31-45-44 backend]# cat .env #キーの確認
APP_NAME=Laravel
APP_ENV=local
APP_KEY=??????????????????????????= #ここで問題なく設定されてますね！
APP_DEBUG=true
APP_URL=http://localhost

```

③.env、database.phpの設定
・.envの設定

```
#各RDSの設定内容を入力
DB_CONNECTION=mysql
DB_HOST=database-1.??????????.ap-northeast-1.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=laravel_zaiko 
DB_USERNAME=admin 
DB_PASSWORD=????? #マスターパスワード
```

・/config/database.phpの設定
env()で囲んである箇所は.envの内容を読み込むようになっていますが、第二引数に直接書き込んでも大丈夫です。
また、RDSに登録したDBの内容はコンソールのRDS画面でDBを選択すれば確認ができます。

```
'default' => env('DB_CONNECTION', 'mysql'),

'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', 'database-1.???????????.ap-northeast-1.rds.amazonaws.com'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'laravel_zaiko'),
            'username' => env('DB_USERNAME', 'admin'),
            'password' => env('DB_PASSWORD', '??????'),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
```

設定が完了したらmigrateしてDBが作成されているか確認しましょう。
前回一度migrateしてるので、今回はリフレッシュします。


```
[root@ip-172-31-45-44 backend]# php artisan migrate:refresh
Migration table created successfully.
```

・DBが作成されているか確認

```
#mysqlログインコマンド
$ mysql -h database-1.????????.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p
```

また、ログインコマンド実行後にパスワードの入力を求められますが、そちらは自身で設定したマスターパスワードになります。
※もしマスターパスワードを忘れた場合はこちらの手順で簡単にパスワードを変更できます。

```
[ec2-user@ip-172-31-45-44 ~]$ mysql -h database-1.????????.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p

Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 8.0.23 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show databases; #DB確認
+--------------------+
| Database           |
+--------------------+
| information_schema |
| laravel_zaiko      |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
```

無事作成できてますね！

3.アプリ起動確認
ここで、アプリへアクセスしてみると下記のようにエラーが発生します。

```
laravel failed to open stream: Permission denied
```

これは、権限の問題でログが書き込みできないというエラーになります。

https://akizora.tech/laravel-log-error-4495

storageディレクトリの権限を変更してあげましょう。
これで問題なくアプリが起動するようになるかと思います。

```
[root@ip-172-31-32-183 backend]# chmod -R 777 storage
[root@ip-172-31-32-183 backend]# client_loop: send disconnect: Broken pipe
```


再度アプリへアクセスしてみると、今度は無事に起動できました！

![スクリーンショット 2022-01-09 15.39.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/1f4c1076-0728-e59a-dc71-8127e5704981.png)


4.シンボリックリンク作成
では、最後にシンボリックリンクの作成やS3バケットの設定など、アプリ動作に必要な準備をしていきます！

```
[root@ip-172-31-45-44 backend]# php artisan storage:link
The [/var/www/laravel-zaikokanri/backend/public/storage] link has been connected to [/var/www/laravel-zaikokanri/backend/storage/app/public].
The links have been created.
```

5.S3バケットの設定
画像アップロード機能を使えるようにする為に.envへS3の設定を追加していきます。

```
[root@ip-172-31-45-44 backend]# vi .env
AWS_ACCESS_KEY_ID=???????????????
AWS_SECRET_ACCESS_KEY=????????????????
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=zaikokanri
```

設定内容が入力できたら、.envの修正内容を反映させる為にキャッシュをクリアします。

```
[root@ip-172-31-32-183 backend]# php artisan cache:clear
Application cache cleared!
```

6.ログインアカウント作成
もし、管理者やダミーユーザーなどのユーザーアカウントをシードに用意してる場合は、シードを実行しておきましょう！

```
[root@ip-172-31-45-44 backend]# php artisan db:seed --class=UserSeeder
Database seeding completed successfully.
```

##最後に
これでEC2インスタンスの複製と再デプロイは終了になります！
結構長くなってしまいましたが、是非少しでも参考になればと思います！