Chromebook(ARM64)にLinux + Docker + PHPStormな開発環境を構築する

# この記事を書いたきっかけ

Amazon Prime Dayは偉大。どうせ買ったChromebookどこまで使えるのか普段仕事で使っている開発環境同等のものを構築してみました。

# 環境・スペックなど

Lenovo Chromebook S330 14.0型 タッチ機能なし 英語キーボード 4GBメモリー 64GB eMMC 型番81JW0011JE ビジネスブラック

# この記事のためにやった事

- Chromebook標準のLinux（ベータ）をインストール
- PHP7.2.20 + composerをインストール
- Laravelを単体で起動
- Dockerとdocker-composeをインストール
- OpenJDKをインストール
- PhpStormをインストール
- anyenv + nodenv + nodeをインストール
- 上記でDocker上にLaravelを起動しPhpStormから操作する

# 手順

## Linux（ベータ）をインストールし起動する

ChromeOSに標準でLinux環境が来たのでそれを利用します（まだベータ版ですが）。

1. 「設定」＞「Linux（ベータ版）」＞「オンにする」
1. 「ChromebookにLinux（ベータ版）をセットアップ」＞「インストール」
1.  数分〜数十分でターミナルが起動したらOK

自分は最初一時間ほど待ったのですが、それ以降powerwash（ChromeOSの初期化）を行ってから再実行したら数分で終わるようになりました。たまたま初回になにかがおかしかったのかもしれません。

## Linux環境のユーザパスワードを設定しておく

必要ないかもしれませんが、念の為。パスワードを聞かれたら同じパスワードを２回入力します。

```bash
$ sudo passwd `whoami`
```

## Linux環境のアップデート

念の為。

```bash
$ sudo apt-get update
$ sudo apt-get upgrade
```

## Linux環境にPHPをインストール

ChromeOSのLinuxはDebian stretchですが、PHPは標準で7.0です。そのためDebian向けPHPパッケージを公開してくれている以下のサイトからインストールします（公式ではないのでご利用は計画的に）。
自力でPHPをインストールする方法もありますが、試したところ7時間ほどかかりましたのであまりおすすめはしません。念の為その方法も最後に書いておきます。

https://deb.sury.org/

```bash
$ curl https://packages.sury.org/php/README.txt | bash
$ sudo apt install -y php7.2 php7.2-mbstring  php7.2-xml php7.2-gd php7.2-zip sudo sqlite3 php7.2-sqlite3 php7.2-mysql
$ php -v
PHP 7.2.20-1+0~20190710.23+ debian9~1.gbp2428c5 (cli) (built: Jul 10 2019 07:46:03) ( NTS )
（後略、インストールを確認）
```

## Linux環境にcomposerをインストール

おなじみのアレです。特に変わったことはありません。

```bash
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
$ sudo chmod +x /usr/local/bin/composer
$ composer --version
Composer version 1.8.6 2019-06-11 15:03:05
（インストールを確認）
```

## Linux環境のIPアドレスを確認

ChromeOSから見たLinux環境のIPアドレスの確認方法です。

```bash
$ ip a
（前略）
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 100.115.92.195/28 brd 100.115.92.207 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link 
       valid_lft forever preferred_lft forever
（後略）
上記の場合、Linux環境のIPアドレスは”100.115.92.195”
```

## Linux環境にLaravelをテストインストール・起動

ここまでのインストールが正しくできているか確認するために、Laravelを簡易的に起動してChromeOS側のGoogle Chrome（ブラウザ）で見えるか確認してみます。

```bash
$ composer create-project laravel/laravel test
$ cd test
$ php artisan serve --host 0.0.0.0
Laravel development server started: <http://0.0.0.0:8000>
```

前述「Linux環境のIPアドレスを確認」でわかったIPアドレスの8000番ポートにChromeOSのChrome（ブラウザ）でアクセスし、Laravelの初期画面が表示されれば成功です。
"--host"オプションをつけないと、'127.0.0.1'で起動してしまい、Linux環境のローカルからしかアクセスできないため、明示的に'0.0.0.0'を指定しています。
アクセス先URL例）http://100.115.92.195:8000/

終わったら"ctrl+c"でLaravelを終了します。

## Linux環境にDockerをインストール

基本的に https://docs.docker.com/install/linux/docker-ce/debian/ の通り

```bash
$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg2 \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository \
   "deb [arch=arm64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
$ sudo usermod -aG docker `whoami`
（Chromebookを一旦終了し、改めて起動した上でターミナルを立ち上げる）
$ id
（出力に”999(docker)”が含まれていればOK）
$ docker run --rm hello-world
```

いろいろと出力されて、その中に”Hello from Docker!”が含まれていればOKです。

## docker-composeをインストール

公式サイトで配布されているdocker-composeはx86_64用のためARM64のChromebookでは利用できません。githubからソースを持ってきてビルドできるのですが、自分が試したところライブラリが正しくリンクされずエラーとなったので、今回はpipでインストールしてみました。

```bash
$ sudo apt-get install python3-pip libffi-dev libssl-dev
$ sudo pip3 install --install-option="--prefix=/usr/local" docker-compose
$ docker-compose --version
docker-compose version 1.24.1, build 4667896
```

## Linux環境にOpenJDKをインストール

PhpStormを起動するのにJavaの実行環境が必要なので、OpenJDKをインストールします。apt-getでインストールされるJDKのバージョンは8です、11か12がいいなと思ったのですが特に問題が出ていないのでそのままにしています。

```bash
$ sudo apt-get install openjdk-8-jdk
$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-2~deb9u1-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)
```

## Linux環境にPHPStormをインストール

こちら( https://medium.com/@budding.technologist/using-intellij-and-other-linux-apps-on-your-chromebook-51fd7fadb9db )を参考にしました

1. https://www.jetbrains.com/phpstorm/download/#section=linux からダウンロード
1. 「ダウンロード」フォルダの中の”PhpStorm-2019.1.3.tar.gz（2019/07/20現在）”を「Linuxファイル」フォルダにコピー
1.  /opt/以下に展開し`phpstorm.sh`を実行してしばらく待つとセットアップ画面が起動します。

```bash
$ sudo tar xvf PhpStorm-2019.1.3.tar.gz -C /opt/
$ /opt/PhpStorm-191.7479.51/bin/phpstorm.sh
```

セットアップ中の"Create Desktop Entry"と"Create Launcher Script"は正しく動作しないので、チェックボックスをオフにした状態で"Next"をクリックしてください。

## Linux環境のApache2の終了

先程PHP7.2をインストールしたときにApacheがインストールされ、自動起動設定および起動されているので、終了し自動起動をオフにします。

```bash
$ sudo systemctl stop apache2
$ sudo systemctl disable apache2
```

## Linux環境にanyenvをインストール

Laravel Mixを動かすためにnode.jsをインストールしますが、バージョンをいろいろと替えたいのでanyenv + nodenvでバージョンを替えられるようにします。まずanyenvをインストールします。

```bash
$ git clone https://github.com/anyenv/anyenv ~/.anyenv
$ echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.profile
$ exec $SHELL -l
$ anyenv init
$ anyenv install --init
$ echo 'eval "$(anyenv init -)"' >> ~/.profile
$ anyenv install --list
（対象の言語に対応したxxxenvが一覧されたらOK）
```

## Linux環境にnodenvとnode.jsをインストール

特にハマるところなく、node.jsがインストールできます。

```bash
$ anyenv install nodenv
$ exec $SHELL -l
$ nodenv install --list
（対象のバージョンが一覧される）
$ nodenv install 10.16.0
$ nodenv global 10.16.0
$ node -v
v10.16.0
$ npm -v
6.9.0
```

## テスト用dockerファイル + Laravelプロジェクトファイル一式をgit cloneし起動

自分がテスト用に作成したDocker用ファイルとLaravelのプロジェクトファイル一式を以下で公開してあります。テスト用にcloneし起動してみます。`docker-compose build`は少々時間がかかります。

```bash
$ git clone git@github.com:uehatsu/chromebook-laravel-docker.git
$ cd chromebook-laravel-docker
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec web bash
(docker)# composer install
(docker)# cp .env.docker .env
(docker)# php artisan key:generate
(docker)# php artisan migrate
```

先に確認したLinux環境のIPアドレスにChromeでアクセスし、Laravelの画面が表示されればOKです。

## Laravel Mixを試してみる

Linux環境上でLaravel Mixを試してみます。

```bash
$ cd src
$ npm i
$ npm run prod
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   public/css/app.css
        modified:   public/js/app.js

no changes added to commit (use "git add" and/or "git commit -a")
```

`npm run prod`が正しく終了し、`public/css/app.css`, `public/js/app.js` の2ファイルが更新されていればOKです。

## PhpStormでテスト用プロジェクトファイルを開いてみる

さて本題です。普通にPhpStormを立ち上げ、プロジェクトファイルを開き、ソースを修正することはすんなりできました（まぁ当たり前ですが）。ざっとコードをいじったところで以下の点が問題になりました。

1. Dockerに接続できない
1. PhpStorm内のterminalが使えない

まずはDockerに接続できないことには先に進めないので、こちらを直してみることにしました。

### PhpStormからDockerに接続する

普通にDockerの設定を行うと「Unix Socketに繋げない云々」と言われエラーになってしまいます。深くは追っていませんが、Java側でユーザのグループなどを正しく引き継げていない可能性があるので、ここはTCP接続に変えてみます。

```bash
$ sudo vi /etc/systemd/system/multi-user.target.wants/docker.service
```

```
修正前）
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

修正後）
ExecStart=/usr/bin/dockerd --containerd=/run/containerd/containerd.sock
```

```bash
$ sudo systemctl daemon-reload
$ sudo vi /etc/docker/daemon.json
```

```json
{
  "hosts": [
    "unix:///var/run/docker.sock",
    "tcp://0.0.0.0:2375"
  ]
}
```

```bash
$ sudo systemctl restart docker
```

これでPhpStormのDockerの設定で、`TCP Socket` > `Engin API URL:` > `tcp://localhost:2375`を指定すればDockerに接続できるようになります。
PHPUnitの設定をDockerに向け、テストを実施するとオールグリーンになるのが確認できました。

### terminalを起動する（失敗）

terminalを起動するとエラーが出て「idea.logを見てね」と言われるので、PhpStormの`Help` > `Show Log in File Mangaer`を選択するとChromeにログ一覧が表示されるので、その中の`idea.log`を開きます。エラー内容を見ると`/opt/PhpStorm-191.7479.51/lib/pty4j-native/linux/x86_64/libpty.so`が読み込めていないとのこと。x86_64版のlibpty.soなら読み込めないだろうと、ARM64版の`libpty.so`を検索すると`eclipse-cdt-jni`モジュールの中に入っていることがわかりました。とりあえずインストールして、上記の場所においてみます。

```bash
$ sudo apt-get install eclipse-cdt-jni
$ sudo mv /opt/PhpStorm-191.7479.51/lib/pty4j-native/linux/x86_64/libpty.so /opt/PhpStorm-191.7479.51/lib/pty4j-native/linux/x86_64/libpty.so.org
$ sudo ln -s /usr/lib/aarch64-linux-gnu/jni/libpty.so /opt/PhpStorm-191.7479.51/lib/pty4j-native/linux/x86_64/libpty.so
```

ライブラリを読み込ませるためにPhpStormを再起動し、terminalを起動してみます。すると先程のエラーは出ず立ち上がりそうになるのですが、うんともすんとも言わずだんまり。エラーログを見てみると「libpty.soにexec_ptyというシンボルが宣言されてないよ」との事。単純にほかから持ってきた`libpty.so`に置き換えただけではだめなようです。ちょっと調べましたがそれ以上情報はなく「PhpStorm内ではterminalは使えず、標準のターミナルアプリを使う」という代替案に落ち着きました。

## 【おまけ】phpenvによるPHP7.2のインストール

すでにanyenvがインストール済みなので、phpenvをインストールした上でPHP7.2をソースからインストールします。自分の環境ではインストールが完了するまで約7時間かかりました。夜寝て朝起きてもまだやってる状態でした。
簡便のために`apt-get build-dep`を利用していますが、本来必要のないモジュールまでインストールされてしまうため本当なら明示的に指定したほうが良いのですが、php-buildの公式ページに書いてある方法ということでそのまま採用しています。以下細かい説明はしません、備忘ということで。

```bash
$ anyenv install phpenv
$ exec $SHELL -l
$ sudo add-apt-repository -s "deb https://deb.debian.org/debian stretch main"
$ sudo apt-get update
$ sudo apt-get install libmcrypt-dev libreadline-dev
$ sudo apt-get build-dep php7.0-cli
$ phpenv install --list
Available versions:
...
7.2.20
...
$ time phpenv install 7.2.20
...
$ phpenv global 7.2.20
$ php -v
...
```

# まとめ

上記を行えばChromebookで一通りの開発環境はできるのですが、やはり強引にARM64アーキテクチャ上で動かしているのでいろいろと問題も出てきます。普段はJISキーボードを使っているので、最初なれなかったキーボードの配列も徐々になれてきたんですが、terminalが動かなかったり、テスト実行時にDockerコンテナが起動するのにちょっと時間がかかったりと完全な状況は作れず、とりあえずLinux入れて開発環境作ってみたという自己満足的なエントリーになってしまいました。ひとまずChromeOSの特性などを勉強できたというのと、それを皆さんに共有できたということでここは良しとします。