18.04bionicにHHVMを入れて試してみる

$ sudo apt install hhvm
$ hhvm –version
HipHop VM 3.21.0 (rel)
Compiler: 3.21.0+dfsg-2ubuntu2
Repo schema: ebd0a4633a34187463466c1d3bd327c131251849

$ echo ‘‘ >/tmp/hello.php
$ hhvm /tmp/hello.php
Hello HHVM

echo "hello world!";

$ hhvm hello.php

Fatal error: /home/vagrant/hhvm/hello.php appears to be a Hack file, but you do not appear to be running the Hack typechecker. See the documentation at http://docs.hhvm.com/hack/typechecker/setup for information on getting it running. You can also set `-d hhvm.hack.lang.look_for_typechecker=0` to disable this check (not recommended).

サイトを見ます。
getting-started

$ touch .hhconfig
$ hhvm hello.php
Warning: Hack typechecking failed: server not ready. Unless you have run “hh_client” manually, you may be missing Hack type errors! Once the typechecker server has started up, the errors, if any, will then show up in this error log.
hello world!

とりあえずHHVMの環境つくって動かしてみました ってところより先の記事が少ない。PHP7.0以上が高速になったので、みんな様子見ってところか。

HHVM/Hack

PHPは、ZendEngineというインタプリタエンジンを使って動いている

インタプリタの挙動
1. テキストファイルを読み込む(IO処理)
2. ソースコードをパースしてopcodeに変換(CPU処理)
3. opcodeを順番に実行

Opcacheを用いることで一度変換したopcodeをメモリ上に載せておき、2回目以降の処理はメモリにキャッシュされたopcodeを取り出して実行する

opcodeは中間言語の為、cpuやosなど実行環境に応じて実行される。その為、JavaやCなどのコンパイル言語よりも実行速度が遅い
c++やgolangは最初のコンパイルで機械語まで変換する

### Hip Hop Virtual Machine
PHPやHack言語をx64CPU向けにJITコンパイルするvirtual machine。つまり、Zend Engineで実行する代わりにJITコンパイルして実行する
HHVMはFacebook開発
HHVMはPHP7からは非推奨だが、Hack言語のサポート

### Hack言語
PHPに静的型付け機能を追加し、HHVMに最適化
開始するタグが < ?php ではなく < ?hhで、HTMLに埋め込む形ができない Hackは非同期機能をサポート Wikipedia, baiduなどが採用 PHPフレームワークやライブラリが使えない? -> Codeigniter, cake, laravel, Yiiなど動作する

### Hack言語の機能
Generic(型をパラメータとして与え、型だけ違って処理の内容が同じものを作るときに使う)
Map(keyとvalueをset) / Vector(順番に値を保持) / Set(重複不可) / Pair(2つの値をセット)
Enum(値を列挙)
async, awaitで並列実行
hh_client(実行前に構文チェック)

amazon linux2(vagrant) + Laravel 7.xでDuskを使うまでの手順

Laravelでseleniumを使おうと思ったら、duskというパッケージがあるらしいので、duskをインストールして使っていきます。環境は、vagrant、amazon linux2, laravel 7.2.1です。

### 1.duskインストール
$ php composer.phar require –dev laravel/dusk
– laravel/dusk v5.10.0 requires ext-zip * -> the requested PHP extension zip is missing from your system.

$ sudo yum install php-pecl-zip.x86_64
$ php composer.phar require –dev laravel/dusk

$ php artisan dusk:install
testsディレクトリにBrowserディレクトリが作られる

.env

APP_URL=http://192.168.33.10:8000

### 2.duskテスト
$ php artisan dusk:make LoginTest

/tests/Browser/LoginTest.php

public function test_can_login_successfull(){
        $this->browse(function (Browser $browser) {
            $browser->visit('/login')
                ->type('email', 'foo@hoge.com')
                ->type('password', 'hogehoge')
                ->press('Login')
                ->assertSee('this is subscriber');
        });
    }
$ php artisan dusk
1) Tests\Browser\ExampleTest::testBasicExample
Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {"capabilities":{"firstMatch":[{"browserName":"chrome","goog:chromeOptions":{"binary":"","args":["--disable-gpu","--headless","--window-size=1920,1080"]}}]},"desiredCapabilities":{"browserName":"chrome","platform":"ANY","chromeOptions":{"binary":"","args":["--disable-gpu","--headless","--window-size=1920,1080"]}}}

Failed to connect to localhost port 9515: Connection refused

ん? ChromeDriverが入っていない?

### 3.ChromeDriver インストール
$ ./vendor/laravel/dusk/bin/chromedriver-linux –verbose
./vendor/laravel/dusk/bin/chromedriver-linux: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory
$ sudo yum install -y libX11
$ ./vendor/laravel/dusk/bin/chromedriver-linux –v
ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882})

$ php artisan dusk
1) Tests\Browser\ExampleTest::testBasicExample
Facebook\WebDriver\Exception\UnknownErrorException: unknown error: cannot find Chrome binary

なに、今度はChrome binary?

### 4.Chrome install
$ curl https://intoli.com/install-google-chrome.sh | bash
$ php artisan dusk

1) Tests\Browser\LoginTest::test_can_login_successfull
Facebook\WebDriver\Exception\NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"body textarea[name='email']"}
  (Session info: headless chrome=80.0.3987.149)

どういうこと? 

### 5.visitでパスを直接指定

public function test_can_login_successfull(){
        $this->browse(function (Browser $browser) {
            $browser->visit('http://192.168.33.10:8000/login')
                // ->dump();
                ->type('email', 'foo@hoge.com')
                ->type('password', 'hogehoge')
                ->press('Login')
                ->assertSee('this is subscriber');
        });

    }
$ php artisan dusk
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 2.18 seconds, Memory: 18.00 MB

OK (1 test, 1 assertion)

上手くいきました。半日かかりましたが、seleniumが何やってるかは理解できました。

Seleniumとは?

公式:selenium
=> Selenium automates browsers
=> 自動でブラウザを操作することで、Webサイトの動作テストを行うことができる(結合試験、総合試験などに活用)
=> 自動で画面キャプチャを保存できる
=> Seleniumには旧API(Selenium RC)と新しいSelenium Web Driverがある
=> Selenium WebDriverはブラウザの拡張機能やOSのネイティブ機能を利用
=> Apache License 2.0, 「Windows」「OS X」「Linux」「Solaris」などをサポート

JSON Wire ProtocolというRESTful API*に対応しており、このAPIにしたがってリクエストすることでブラウザを操作することができる

JSON Wire Protocol ↔︎ Firefox Driver | Chrome Driver | IE Driver ↔︎ ブラウザ拡張機能/OSのネイティブ機能 ↔︎ ブラウザ

### 注意点
– テストコードが冗長になる
– 非同期処理は苦手

LaravelでSeleniumを使うには?
-> Duskというテストフレームワークが含まれている
-> DuskはPHPUnitとphp-webdriver、seleniumを使うためのパッケージ

Laravel7.x、EC2でphp artisan down –allow=${ip}が効かない時

本番環境でメンテナンスモードにして、特定のIPだけ操作を許可したい場合は、

$ php artisan down --allow=${ip}

と書く。EC2で実行したところ、指定したipでもメンテナンスモードの画面に。

EC2 ELB: ELBを使って、SSL対応している

ELBを挟んでいるため、ip取得のclassにHTTP_X_FORWARDED_FORを追加する
$ sudo vi vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php

public function handle($request, Closure $next)
    {
        if ($this->app->isDownForMaintenance()) {
            $data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true);

            // 追加
            if (isset($data['allowed']) && IpUtils::checkIp($request->server->get('HTTP_X_FORWARDED_FOR'), (array) $data['allowed'])) {
                return $next($request);
            }

            if (isset($data['allowed']) && IpUtils::checkIp($request->ip(), (array) $data['allowed'])) {
                return $next($request);
            }

            if ($this->inExceptArray($request)) {
                return $next($request);
            }

            throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']);
        }

        return $next($request);
    }

※HTTP_X_FORWARDED_FOR: リバースプロキシを挟んだアクセス元のIPを取得する

これで、メンテナンスモード時に、特定IPのみ操作できるようになります。
$ php artisan down –allow=${myIP}
$ php artisan up

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日様子を見よう。

minikubeでcreate deployment

$ sudo kubectl get nodes
$ sudo kubectl describe nodes ubuntu-bionic
$ sudo kubectl proxy
Starting to serve on 127.0.0.1:8001

※kubectlはクラスタのマスターノード上で実行される

$ sudo kubectl get pods -o wide
No resources found in default namespace.
$ sudo kubectl get pods -o json
{
“apiVersion”: “v1”,
“items”: [],
“kind”: “List”,
“metadata”: {
“resourceVersion”: “”,
“selfLink”: “”
}
}

### hello-minikube
// pod, deployment作成
$ kubectl run hello-minikube –image=k8s.gcr.io/echoserver:1.4 –port=8080
// get deployment
$ sudo kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-minikube 0/1 1 0 2m
// serviceを使う
$ sudo kubectl expose deployment hello-minikube –type=NodePort
service/hello-minikube exposed
$ sudo minikube service hello-minikube –url
$ curl http://192.168.33.10:30835
CLIENT VALUES:
client_address=172.17.0.1
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://192.168.33.10:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 – lua: 10001

HEADERS RECEIVED:
accept=*/*
host=192.168.33.10:30835
user-agent=curl/7.58.0
BODY:
-no body in request-v

### hello-node
$ sudo kubectl create deployment hello-node –image=gcr.io/hello-minikube-zero-install/hello-node

$ sudo kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-minikube 1/1 1 1 38m
hello-node 1/1 1 1 21m

$ sudo kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-75cb6dd856-8rxx7 1/1 Running 0 38m
hello-node-7676b5fb8d-hdj6d 1/1 Running 0 21m

$ kubectl expose deployment hello-node –type=LoadBalancer –port=8080
$ sudo kubectl get services
$ curl http://192.168.33.10:32720
Hello World!

kubectl createでDockerコンテナを使用してpodを作成する
Deploymentを作成するとDeployment、replicaset, Podが作られる

k8sのアーキテクチャ

マスターコンポーネントでnodeを制御している
コンテナはnodeのpodの中で実行される
minikubeではマスターとウォーカーは同じサーバだが、k8sでは別サーバ

ロードバランサの役割もk8sでやってしまうイメージか。
create deploymentでGCPからimageをpullしているけど、実務上ではDockerfileでコンテナの仕様を書いていくと思うんだが、その場合のnode、podはどうやって作成して関連付けていくのか良く解らんな。サンプルじゃなくて、実際にアプリを作らないときついか?

18.04(bionic)でminikube🐳

$ uname -a
Linux ubuntu-bionic 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ git –version
git version 2.17.1

### kubectl install
$ sudo snap install kubectl –classic
$ kubectl version
Client Version: version.Info{Major:”1″, Minor:”17″, GitVersion:”v1.17.3″, GitCommit:”06ad960bfd03b39c8310aaf92d1e7c12ce618213″, GitTreeState:”clean”, BuildDate:”2020-02-12T13:43:46Z”, GoVersion:”go1.13.7″, Compiler:”gc”, Platform:”linux/amd64″}

### Docker install
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –
$ sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”
$ sudo apt-get update
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io
$ sudo docker –version
Docker version 19.03.8, build afacb8b7f0

### docker-compose
$ 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

### minikube
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ chmod +x minikube
$ sudo cp minikube /usr/local/bin
$ sudo minikube start –vm-driver=none
$ sudo minikube start –vm-driver=none
$ sudo minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntu-bionic Ready master 16m v1.17.3

なんか良く解らないがminikubeが動いているように見える🐳
nodeがminikubeでなく、ubuntu-bionicになってるけど、合ってるのだろうか?

ubuntu14.04(trusty)でminikubeを起動しようと思ったら

ubuntuでkubernetesを学びたい🐳
docker, docker-composeはインストール済

$ uname -a
Linux vagrant-ubuntu-trusty-64 4.4.0-148-generic #174~14.04.1-Ubuntu SMP Thu May 9 08:17:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ docker –version
Docker version 18.06.3-ce, build d7080c1

1. kubectlインストール
2. Minikubeインストール

### kubectlのインストール
k8s公式を参考にする
install-kubectl
$ sudo apt-get update && sudo apt-get install -y apt-transport-https
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add –
$ echo “deb https://apt.kubernetes.io/ kubernetes-xenial main” | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
$ sudo apt-get update
$ sudo apt-get install -y kubectl
$ kubectl version
Client Version: version.Info{Major:”1″, Minor:”17″, GitVersion:”v1.17.4″, GitCommit:”8d8aa39598534325ad77120c120a22b3a990b5ea”, GitTreeState:”clean”, BuildDate:”2020-03-12T21:03:42Z”, GoVersion:”go1.13.8″, Compiler:”gc”, Platform:”linux/amd64″}

### minikubeインストール
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo chmod +x minikube
$ sudo cp minikube /usr/local/bin
$ sudo minikube start –vm-driver=none
* minikube v1.8.2 on Ubuntu 14.04 (vbox/amd64)
* Using the none driver based on user configuration

! ‘none’ driver reported an issue: exec: “systemctl”: executable file not found in $PATH
* Suggestion: Use a systemd based Linux distribution
* Documentation: https://minikube.sigs.k8s.io/docs/reference/drivers/none/

X none does not appear to be installed

あ、14.04は古いのか。サポートも終了しているみたいだし、18.04でやり直そう。。

$ vagrant ssh
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

System information as of Sat Mar 21 05:59:25 UTC 2020

System load: 0.01 Processes: 109
Usage of /: 12.3% of 9.63GB Users logged in: 0
Memory usage: 16% IP address for enp0s3: 10.0.2.15
Swap usage: 0% IP address for enp0s8: 192.168.33.10

0 packages can be updated.
0 updates are security updates.

kubernetes基礎

公式サイト: kubernetes
Kuberntes Github:kubernetes / kubernetes

– 実行環境に依存しない(AWS, GCP, オンプレ)
– Docker以外のコンテナも可
– 複数ホストにコンテナをデプロイ
– サーバ台数関係なく、コンピュータ資源を最適化して複数のapplicationを起動できる(コンテナのリソースアロケーション)
– 負荷に応じてapplicationごとに自動で数を増減できる(コンテナの負荷分散)
– サーバを入れ替えることなくapplicationのデプロイが可能

masterとよばれる親機とnodeとよばれる子機サーバを用意して、kubernetesをそれぞれインストールして通信設定
ECSやGKEなどkubernetesマネージドサービスがある

k8sの構成は以下の通り
Ingress(通信内容をServiceにプロキシする)
Service(複数のPodに対して単一IPアドレスを割り当てる機能) ロードバランサのように振る舞う。ClusterIP、NodePort, LoadBalancer, ExternalNameなど
Cluster
L Node(コンテナをデプロイするための物理サーバ) k8sを管理するデーモンはNode上で実行
L Pod(デプロイの最小単位) 
L コンテナ

MiniKube:ローカルのVM内にk8sクラスタ内のコンテナを操作するためのKubernetesMasterと単一ノードのk8sクラスタを構築する

まずはminikubeで理解していくってことか?