EC2のmysql8.0.19でmmap(137363456 bytes) failed; errno 12

EC2でmysqlが頻繁に落ちる。
暫定的に以下を実行すると再起動できるが、1日経つとまた落ちる。

sudo touch /var/lib/mysql/mysql.sock
sudo chmod 777 /var/lib/mysql/mysql.sock
sudo service mysqld restart

cronの実行が影響しているのか? cronを止めて、PDOを手動実行するも問題なし。

ログを確認するとmmap(137363456 bytes) failed;となっている

$ sudo cat /var/log/mysqld.log
2020-03-21T20:45:21.161522Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.19) starting as process 12458
2020-03-21T20:45:21.299847Z 0 [ERROR] [MY-012681] [InnoDB] mmap(137363456 bytes) failed; errno 12
2020-03-21T20:45:21.299951Z 1 [ERROR] [MY-012956] [InnoDB] Cannot allocate memory for the buffer pool
2020-03-21T20:45:21.300002Z 1 [ERROR] [MY-012930] [InnoDB] Plugin initialization aborted with error Generic error.
2020-03-21T20:45:21.301125Z 1 [ERROR] [MY-010334] [Server] Failed to initialize DD Storage Engine
2020-03-21T20:45:21.301283Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
2020-03-21T20:45:21.301362Z 0 [ERROR] [MY-010119] [Server] Aborting
2020-03-21T20:45:21.306253Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19)  MySQL Community Server - GPL.

innodb_buffer_pool_sizeを超えていることがわかる

mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+
1 row in set (0.00 sec)

buffer_pool_sizeを256Mに変更
$ sudo vi /etc/my.cnf

[mysqld]
innodb_buffer_pool_size = 256M

$ sudo service mysqld restart
mysql> SHOW VARIABLES LIKE ‘innodb_buffer_pool_size’;
+————————-+———–+
| Variable_name | Value |
+————————-+———–+
| innodb_buffer_pool_size | 268435456 |
+————————-+———–+
1 row in set (0.02 sec)

これで2~3日様子を見よう。

EC2(amazon linux2)上でDockerを使う

テスト用ですぐにterminateするため、EC2のスペックは最小限にします

### Launch instance
– Amazon Linux 2 AMI (HVM), SSD Volume Type
– type: t2.nano
– subnet: public
– Auto-assign Public IP: enable
– volume: GP2 8Gib
– Security Group: HTTP 0.0.0.0/0, SSH 0.0.0.0/0

### 前準備
$ ssh ec2-user@${public ip} -i ~/.ssh/${秘密鍵}.pem

// git install
$ sudo yum update
$ sudo yum -y install gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker autoconf
// 省略

### EC2にDocker.ceインストール
// Extras Libraryを見てみる
$ amazon-linux-extras
20 docker=latest enabled \
[ =17.12.1 =18.03.1 =18.06.1 =18.09.9 =stable ]
$ amazon-linux-extras info docker
docker recommends docker # yum install docker

ありますね、extrasからインストールします。
$ sudo amazon-linux-extras install docker
$ docker –version
Docker version 18.09.9-ce, build 039a7df

### Docker-compose install
$ sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose –version
docker-compose version 1.21.2, build a133471

## docker構築
### docker-compose.yml & Dockerfile
-docker-composeの構成やimageはlocal環境(ubuntu)と同じにする
-> nginx:1.13.5-alpine, node:12.13.0-alpine&php:7.3-fpm-alpine, FROM mysql:5.7.19

$ docker-compose build
ERROR: Couldn’t connect to Docker daemon at http+docker://localhost – is it running?
あれ?
$ sudo docker-compose build
sudo: docker-compose: command not found
ん?

権限をec2-userに付与する
$ sudo usermod -a -G docker ec2-user
$ cat /etc/group |grep docker
docker:x:993:ec2-user

$ docker info
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
あれ?

$ sudo service docker start
$ sudo docker info

### build & up -d
$ docker-compose build
$ docker-compose up -d
$ docker-compose ps
Name Command State Ports
———————————————————————-
app-1 docker-php-entrypoint php-fpm Up 9000/tcp
db-1 docker-entrypoint.sh mysql … Exit 1
nginx-1 nginx -g daemon off; Up 0.0.0.0:80->80/tcp
ん?
$ docker logs db-1

EC2でもswapメモリを増設する
$ sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
$ sudo /sbin/mkswap /var/swap.1
$ sudo /sbin/swapon /var/swap.1

$ docker-compose ps
Name Command State Ports
————————————————————————-
app-1 docker-php-entrypoint php-fpm Up 9000/tcp
db-1 docker-entrypoint.sh mysql … Up 0.0.0.0:3306->3306/tcp
nginx-1 nginx -g daemon off; Up 0.0.0.0:80->80/tcp

### 動作確認
$ docker exec -it app-1 sh
/var/www/html # ls
index.html index.php
$ docker exec -it nginx-1 sh
/ # cd /var/www/html
/var/www/html
$ docker exec -it db-1 bash
root@3e44157ee4fc:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.19 MySQL Community Server (GPL)

publicIPを叩く
http://**.***.***.***/
-> OK

なるほど、ローカルと全く一緒なので割と直ぐに環境構築ができます。
any application, anywhereが実感できる。
EC2の場合は冗長化が前提なので、mysqlのコンテナは必要なしでRDSに繋げるところが異なるか。vagrantが長かったせいか、商用環境にコンテナを使うのは違和感があったが、実際動かしてみると、Dockerでも別に差し支えないように見える。

インフラに変更を加えなければ、デプロイはCodeDeployで対応できそうだが、パッケージ等を入れるにしても、Dockerfileを更新するだけってのは確かに良いかも。
そして、デプロイやロードバランサまわり、オートスケーリングなどをkubernetesで管理するのね。

EC2をprivate subnetに移し、SSH用のbastionサーバの構築

### 既存のWebサーバのAMIを取得
Instances -> Actions -> Image -> Create Image

### purivate subnetのインスタンスの作成
作成したAMIから、再度インスタンスを作る
${appName}-prd-01-private
vpc:dev-vpc
subnet:dev-subnet-private1
Public IP:enable
IAM role: s3readonly
Security group: prd

${appName}-prd-02-private
vpc:dev-vpc
subnet:dev-subnet-private2
Public IP:enable
IAM role: s3readonly
Security group: prd

### public subnetのインスタンス削除
instance -> instance state -> terminate

### ALBのターゲットグループに追加
TargetGroup -> Target -> 追加
->ALBのDNSを叩いて動作確認
->コンソールからinstanceのpublic ipを叩いてssh接続できない事を確認

### bastionのサーバ構築
Instance Type: t2.nano
VPC: dev-vpc
subnet: dev-public-subnet
Auto-assign Public IP: enable
storage size: 8Gib
tag: ${appName}-prd-bastion
security group: create ${appName}-sg-bastion, Custom TCP
key pair: 新規推奨

### bastionのkey pair
bastionサーバにログインし、home/ec2-user/.sshに 秘密鍵(***.pem)を配置する
bastionにSSHログイン

$ ssh ec2-user@*** -i  ~/.ssh/***.pem
$ sudo chmod 600 /home/ec2-user/.ssh/***.pem
$ cd .ssh
$ ls -l

### Webサーバのセキュリティグループ
ssh接続のソースをmyIPに変更

### bastionからprivate subnetのweb serverにログイン
$ ssh ec2-user@${private_ip} -i .ssh/aws-dev.pem

$ curl https://www.google.co.jp/
-> timeout
-> private subnetは、インターネットゲートウェイのルーティングが存在しないことが原因

### NATゲートウェイ作成
VPC -> NATGateways -> create
subnet: dev-subnet-public1
Elastic IP: 割り当て

Private route table
NAT Gateway 割り当て

curl https://www.google.co.jp/
-> レスポンスが返るようになる。

ansible-playbookでvagrantからEC2にデプロイする方法

[EC2側]
まず、EC2を起動し、ターミナルからssh接続
$ ssh ec2-user@**** -i ~/.ssh/***.pem
$ cd /home/release
$ ls
LICENSE appspec.yml index.html scripts

[vagrant側]
.ssh/、inventory/hostsを作成済み
/hosts

[targets]
**.***.**.**

今回デプロイするtest.htmlを作成する

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	ansible deploy test
</body>
</html>

$ ls
LICENSE appspec.yml index.html inventory playbook.yml scripts test.html

playbook.yml

- hosts: targets
  sudo: yes
  tasks:
    - name: put test.html
      copy: src=test.html dest=/home/release/ owner=root group=root mode=640

### デプロイ実行
$ ansible-playbook -i inventory/hosts –private-key=.ssh/***.pem playbook.yml -u ec2-user
PLAY [targets] *****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [**.***.**.**]

TASK [put test.html] ***********************************************************
changed: [**.***.**.**]

PLAY RECAP *********************************************************************
**.***.**.** : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

### EC2側で確認
$ ls
LICENSE appspec.yml index.html scripts test.html
$ sudo cat test.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	ansible deploy test
</body>
</html>

playbook.ymlは、デプロイする場合は、copy: src=${source file} dest=${dest directory} owner=root group=root mode=640 でOK
test.htmlを修正して、再度ansible-playbookを叩いた場合でも、EC2側で反映されていることが確認できます。

ansibleでvagrantからEC2にSSH接続するテスト

Githubではなく、ローカルからEC2にデプロイしたい時もあるでしょう。
という事で、AnsibleからEC2にSSH接続する方法を確認していきます。

### 前提
– vagrantにansibleインストール済

$ ansible –version
ansible 2.8.5

### .gitignore
git pushする際に、秘密鍵がレポジトリにpushされないよう、gitignoreを設定します。
.gitignore

/.ssh

.ssh フォルダにテストファイルを作成して.gitignoreが動くかテスト
$ git add .
$ git commit -m “gitignore added”
$ git push -u origin master

レポジトリにて、.sshがpushされていない事を確認

## -m pingテスト
### .ssh
ec2の秘密鍵を.sshに配置
$ chmod 700 .ssh/

### EC2
instanceからEC2をstart

### host
inventory/hosts
-> instanceのpublic ip(テスト用)を入れる

[targets]
**.***.**.**

### ansible command
$ ansible all -i inventory/hosts -m ping

**.***.**.** | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Warning: Permanently added '**.***.**.**' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic).", 
    "unreachable": true
}

鍵認証が上手くいっていない。

$ ansible all -i inventory/hosts –private-key=.ssh/***.pem -m ping -u ec2-user

**.***.**.** | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

EC2起動からLaravelプロジェクトのデプロイまで

### 1. elastic ipをインスタンスに割り当て & security groupにhttp追加
-elastic ipをインスタンスに割り当て
-security groupのruleにHTTPを追加

### 2. ssh ログイン
ssh ec2-user@${elastic ip} -i ~/.ssh/***.pem

### 3.ec2-user グループ
$ sudo groupadd www
// ユーザー(ec2-user)を www グループに追加
$ sudo usermod -a -G www ec2-user
$ groups

### 4. rootユーザpass変更
$ sudo su –
$ passwd

### 5. git install
// 省略

### 6. Node.js install
// 省略

### 7. Apache HTTP Server
// 省略

### 8. php 7.3 install
// 省略

### 9. MySQL 8.0 install
// 省略 インスタンスタイプがnanoだとmemory不足となるので要注意

### 10. ansible install
// 省略

### 11. date time変更
// 省略

### 12. *.conf の設置
$ sudo mkdir /var/www/log
$ sudo vi /etc/httpd/conf.d/custom.conf

# エラーログ
ErrorLog "/var/www/log/error_log"

# アクセスログ
<IfModule log_config_module>
    CustomLog "/var/www/log/access_log" combined
</IfModule>

### 13. git clone
$ sudo git clone https://github.com/***/***.git

// ドキュメントルート変更
$ sudo vi /etc/httpd/conf.d/custom.conf

DocumentRoot "/var/www/hoge/public"

# .htaccess 有効化
<Directory /var/www/hoge/public>
    AllowOverride All
</Directory>         

### 14. パーミッション変更
$ sudo chmod -R 777 hoge/storage
$ sudo chmod -R 775 hoge/bootstrap/cache
// /var/www とそのコンテンツのグループ所有権を www グループに変更
$ sudo chown -R root:www /var/www

### 15. project
$ curl -sS https://getcomposer.org/installer | php
$ sudo php composer.phar install
$ sudo php composer.phar dump-autoload
$ sudo php artisan key:generate
// 省略

### 16. Elastic ipにアクセスし、動作確認
http://***/login
http://***/register

EC2の起動からSSH接続までの一連の流れ

### 前提条件
– MFA認証のIAMユーザ作成済
– VPC、public subnet、InternetGateway、RouteTable作成済
– セキュリティグループ作成済
– Key Pairsで秘密鍵・公開鍵作成済

### EC2
1. launch instance
2. Amazon Linux 2 AMI (HVM), SSD Volume Type 64bit(x86)
3. Choose instance type
4. networkで作成したVPC、public subnetを設定(InternetGateway紐付け済)
  Auto-assign Public IPをenableにする disableのままだと、privateしか割り当てられない
5. storage sizeはdefaultの8GiB
6. Add tag: keyにdev, valueにdev-testとする
7. Configure Security Groupで作成したsecurity groupを紐付け(ssh許可)
8. 作成したkey pairを選択
※VPCのDNS resolution、DNS hostnamesがEnabledになっていることを確認。desabledの場合はactionで変更。instanceを再起動

接続

ssh ec2-user@${public ip} -i  ~/.ssh/***.pem

cyberduckでも同様に、ssh-private keyで.pemを指定すると、接続できる。

お、お、お、お疲れ様でしたー

EC2のKey Pairs作成(mac編)

### Key Pairs作成
– EC2のleft paneのNetwork & Security -> Key Pairsを選択
– Create key pair
– Name: aws-dev(file formatはpem)

### macの.sshに保存
$ pwd
/Users/${username}
$ ls -a
$ cd .ssh
$ ls
aws-dev.pem

アクセス権限の変更: オーナーのみ読み出しができる400(所有者:R)
$ sudo chmod 400 aws-dev.pem 
$ ls -l
-r——–@

pemファイルは秘密鍵
流れとしては
1. ssh接続要求
2. aws側でランダムデータを生成し、公開鍵を使ってクライアントに送る
3. 受け取ったクライアント側は秘密鍵でデータを復号化して送り返す
4. aws側でランダムデータと受け取った復号化データを比較して認証する

このような仕組みから、key parisはAWSで生成するのではなく、ローカルマシンでの生成が望ましい。
$ ssh-keygen -t rsa -f hoge.pem

linux timezone変更手順

$ date
$ cat /etc/localtime
TZif2UTCTZif2?UTC
UTC0
$ sudo cp /etc/localtime /etc/localtime.org
$ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ sudo cp /etc/sysconfig/clock /etc/sysconfig/clock.org
$ sudo vi /etc/sysconfig/clock

ZONE="Asia/Tokyo"
UTC=false

$ strings /etc/localtime
$ date

php build-in serverでhttpsサーバーを起動

ローカル環境で、httpsの挙動を確認したい時に使えるのが、hyper-builtinというライブラリ
https://github.com/mpyw/php-hyper-builtin-server

opensslでサーバー証明書を生成し、composerでhyper-builtinを入れて起動
※下はawslinuxだが、centosでも同様

### sslモジュールインストール(centOSの場合はmod_ssl)
$ sudo yum install mod24_ssl
$ httpd -M | grep ssl

### 秘密鍵作成
$ openssl genrsa > server.key

### CSR作成
$ openssl req -new -key server.key > server.csr

### サーバー証明書作成
$ openssl x509 -req -signkey server.key < server.csr > server.crt
$ rm server.csr

### 秘密鍵&サーバー証明書配置
$ sudo mkdir /etc/httpd/conf/ssl.key
$ sudo mkdir /etc/httpd/conf/ssl.crt
$ sudo mv server.key /etc/httpd/conf/ssl.key/
$ sudo mv server.crt /etc/httpd/conf/ssl.crt/

### ssl.conf編集
sudo vi /etc/httpd/conf.d/ssl.conf

# SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
# SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key

### apache再起動
$ sudo service httpd restart

### composerでhttps用のphp buildin-server libraryインストール
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require –dev mpyw/php-hyper-builtin-server:^2.0

### httpsサーバー起動
$ vendor/bin/hyper-run -s 192.168.33.10:8000

うおおおおおおおおおおおおおお、めんどくせええええええええええええ
これ、playbook.ymlで一括管理してーーーーーーーーーーーーー