Amplifyの開発をVSCode Remote containerで行う（その２）

前回は、[その１](https://qiita.com/ssugimoto/items/aa902d9e42a4e27990fa)を参照
その２では、Amplify SNS workshop とは別の視点で開発環境を作成する

## その１と違う点
- ワークショップ向けの設定なので、いくつか改変してみる
- nodeのバージョン
- amplifyのバージョン
- コンテナからホスト側を使った開発 `/hostdir` を使う
- プロファイル（aws、ssh）を使う、切替える

- toriさんオリジナルの方では、speeeeedアップのため、コンテナ内での開発 `/workspaces` を使うようになっている
    - コンテナ内だと速さが段違いです。ホスト側を使うと遅いのは DockerとWSL2に起因する問題だと思われる、後述参照。

## Dockerfile
```
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-14

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get -y install --no-install-recommends java-common zip \
    && wget https://corretto.aws/downloads/latest/amazon-corretto-8-x64-linux-jdk.deb \
    && dpkg --install amazon-corretto-8-x64-linux-jdk.deb \
    && wget https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip \
    && unzip awscli-exe-linux-x86_64.zip \
    && ./aws/install \
    # Clean up
    && rm -f awscli-exe-linux-x86_64.zip \
    && rm -f amazon-corretto-8-x64-linux-jdk.deb \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*
ENV DEBIAN_FRONTEND=dialog

WORKDIR /workspaces
```
WORKDIR は変更せず

### Docker hub
- https://hub.docker.com/_/microsoft-vscode-devcontainers と https://github.com/microsoft/vscode-dev-containers/tree/main/containers/javascript-node より

```
mcr.microsoft.com/vscode/devcontainers/javascript-node:14
mcr.microsoft.com/vscode/devcontainers/javascript-node:16
```

があり、AmplifyはNode14対応なので、バージョンアップできる。
nodeを14使うように変更すると、2021-07-02時点でのコンテナイメージでは V14.17.1 になる。

## devcontainer.jsonを変更
```
{
	"name": "AWS Amplify SampleSystem",

	"dockerFile": "Dockerfile",

	// Set *default* container specific settings.json values on container create.
	"settings": { 
		"terminal.integrated.shell.linux": "/bin/bash"
	},

	// Add the IDs of extensions you want installed when the container is created.
	// Git Extension Pack => "donjayamanne.git-extension-pack"
	// GraphQL => "graphql.vscode-graphql"
	// GraphQL for VSCode => kumar-harsh.graphql-for-vscode
	"extensions": [
		"dbaeumer.vscode-eslint",
		"mhutchie.git-graph",
		"eamodio.gitlens"
		
	],

	// Mount ~/.aws directory for AWS Amplify CLI and AWS CLI access
	// Mount ~/.ssh directory for Git Repository GitHub, GitLab ...
	"mounts": [
		"source=${localEnv:HOME}${localEnv:USERPROFILE}/.aws,target=/root/.aws,type=bind,consistency=cached",
		"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/root/.ssh,type=bind,consistency=cached"
	],

	// Use in-container folder (not mounted host directory) as a workspace to speeeeeeed-up the `npx create-react-app` command. See https://github.com/toricls/aws-amplify-sns-workshop-in-vscode/pull/3.
	// {localWorkspaceFolder} is open folder host path.
	"workspaceMount": "source=${localWorkspaceFolder},target=/hostdir,type=bind,consistency=cached",
	"workspaceFolder": "/hostdir",
	"containerEnv": { 
		"MOUNTED_HOST_DIR": "${localWorkspaceFolder}",
		"MOUNTED_HOST_DIR_PATH_IN_CONTAINER": "/hostdir"
	},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// npm , amplify mock api , 62224 DynamoDB
	"forwardPorts": [3000,20002],

	// Use 'postCreateCommand' to run commands after the container is created.
	"postCreateCommand": "npm install -g @aws-amplify/cli@5.1.0",

	// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
	// "remoteUser": "node"
　　　　　
    // docker container name (Identify Dev Containers)
	"runArgs": [
        "--name=dev_container"
    ]
}
```
---

### name

`"name": "${localWorkspaceFolderBasename}",`
にすると、ディレクトリ名でよしなにやってくれる。Dockerのコンテナ名とは別。

### extensions
- VSCodeの拡張機能を指定する、Git連携するならばVSCodeからGit操作できる拡張機能を入れておく方が良い

---

### mounts
- AWSのクレデンシャルファイルをホスト側のマシンと共有する場合にマウントする
- 案件・プロジェクトでクレデンシャルが異なる場合は、マウント場所を変えるか、マウントせずにコンテナビルド後にファイルを置く

```
- credentials　：aws_access_key_idとaws_secret_access_keyが記載された重要なファイル
- config  ：デフォルトの接続先リージョン
```

- 例えば 以下のようにUSERPROFILEをカレントディレクトリにすれば、credentialsの切替えは楽になる

<details><summary>サンプル</summary><div>

```
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.aws,target=/root/.aws,type=bind,consistency=cached",
```
を

```
"source=./aws,target=/root/.aws,type=bind,consistency=cached",
```
に変更する

</div></details>

---

#### SSH

- git接続等で使う、ssh key をホスト側と共有する場合にマウントする
    - コンテナ内で、ssh key 生成したものを、Windows側にもってきても使えなかった（そうなの？ Mac使ってたから意識したことなかった）。
    - どうやらopen-ssh形式というのが関連している。これだからwindowsは・・・と、言われる。
- 対応例 https://coffee-nominagara.com/2018-06-22-093801

- コンテナ内で ssh key 作成する場合の例

<details><summary>Linux向けのssh key 作成例</summary><div>

```
cd ~/
~/.ssh $ ssh-keygen -t rsa -C "メールのアカウント@ドメイン"

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.


中身を確認
~/.ssh $ cat id_rsa.pub
~/.ssh $ cat id_rsa

pubの方をGithubに登録する

接続してみる
~/.ssh $ ssh -T git@github.com

Hi xxxxx! You've successfully authenticated, but GitHub does not provide shell access.

クローンしてみる
$ git clone git@github.com:xxxxxxx/xxxxxx.git

```
</div></details>

---

---

### コンテナから見るホスト側（コンテナに対し、ホスト側を共有する）
```
	"workspaceMount": "source=${localWorkspaceFolder},target=/hostdir,type=bind,consistency=cached",
	"workspaceFolder": "/hostdir",
	"containerEnv": { 
		"MOUNTED_HOST_DIR": "${localWorkspaceFolder}",
		"MOUNTED_HOST_DIR_PATH_IN_CONTAINER": "/hostdir"
	},
```

上記の箇所が設定で、公式ドキュメントでは https://code.visualstudio.com/docs/remote/containers-advanced

#### `workspaceMount`

- ホスト側の場所を、コンテナ内のどのディレクトリをtargetとし、ホストをsourceとしてマウントする設定になる。
- ホスト側は、「.devcontainer」フォルダのある場所（.devcontainerと同じディレクトリ）がカレントディレクトリになり、コンテナ内の `/hostdir`がその場所になる。
- コンテナ内で `cd /hostdir` して、`ls` すると、（.devcontainerと同じディレクトリにある）ホスト側のファイルが見られる

#### `workspaceFolder` 

- VSCodeでコンテナ内に接続した時のデフォルトの場所、ホスト側と共有した場所がVSCodeで開いたときの最初の場所になる、
- デフォルトがホスト側の場所にしたい場合は `"workspaceFolder": "/hostdir", `を指定する。
- デフォルトが コンテナ内の`/workspaces`が良い場合はそれを指定する。

### コンテナビルドで入れている Amplifyのバージョンを最新に変更
- バージョンは 2021-06-30では 5.0.2、2021-07-01に、Amplify-cliはV5.1.0がリリースされた

```
	"postCreateCommand": "npm install -g @aws-amplify/cli@5.1.0",
```

- ビルド後の処理
`devcontainer.json`の`postCreateCommand` ビルド後の処理が設定できる。ここで個人ごとに設定を行うことも可能。

### runArgsでコンテナの識別、name指定することでコンテナ名をわかりやすくする
```
	"runArgs": [
        "--name=project_dev_container"
    ]
```

## 実際の開発で使った場合
- 注意事項、`/hostdir` はWindows側をマウントしておりwsl2の場合はファイルアクセスが非常に遅いです
1. コンテナ初期化したらいったんVSCodeを閉じて、VSCodeを新規起動する
1. ホスト側で VSCode で コンテナの元になっているディレクトリを開くと、`workspaceFolder`の場所になるので、VSCode -> ツールバー の Terminal -> New Terminal で開くと、`/hostdir` をデフォルトで開く、そしてそこはコンテナの元になっているディレクトリになり、ホスト側の場所でもある。
（ホスト側の場所：docker-composeでvolumesでホスト側をマウントしたときと同じような場所）
1. Terminalを開いて、以下のコマンド実行
<details><summary>コマンド実行例</summary><div>

    ```
	root ➜ /hostdir $ mkdir amplify-sns-workshop
	root ➜ /hostdir $ cd amplify-sns-workshop/
	root ➜ /hostdir/amplify-sns-workshop $ npx create-react-app boyaki
	npx: installed 67 in 2.912s

	Creating a new React app in /hostdir/amplify-sns-workshop/boyaki.

	Installing packages. This might take a couple of minutes.
	Installing react, react-dom, and react-scripts with cra-template...

	....

	root ➜ /hostdir $ mkdir amplify-sns-workshop
	root ➜ /hostdir $ cd amplify-sns-workshop/
	root ➜ /hostdir/amplify-sns-workshop $ npx create-react-app boyaki
	npx: installed 67 in 2.912s

	Creating a new React app in /hostdir/amplify-sns-workshop/boyaki.

	Installing packages. This might take a couple of minutes.
	Installing react, react-dom, and react-scripts with cra-template...


	root ➜ /hostdir/amplify-sns-workshop/boyaki (master) $ amplify init
	root ➜ /hostdir/amplify-sns-workshop/boyaki (master) $ yarn start
    ```
</div></details>

1. 問題なく動いて、
    - `/hostdir/amplify-sns-workshop/boyaki` で進められる。
    - ホスト側の場所でもあるため、  
       `/hostdir` が   
       `C:\usr\aws-tutorial\vsremote-20210703-compose\` ディレクトリだとすると  
       `C:\usr\aws-tutorial\vsremote-20210703-compose\amplify-sns-workshop\boyaki` 
       となり。  
    - ファイルはコンテナ内でもホスト側でも編集できる。  
    - ホスト側のSourceTreeやGitHubDesktop等のGitのGUIクライアントを使うことができる。
1. `yarn start  | npm start` はけっこう時間かかる、処理が終われば http://localhost:3000/ でReactの画面が表示される


---

## （番外編）自分自身の環境
### dockerコンテナ内のファイルを使う場合とWindows側のホストのファイルを使う場合
- コンテナ側 `/workspaces` と ホスト側 `/hostdir` 
- 自身のがdocker desktop で wsl2 Ubuntuでないためか npx のコマンドで10倍以上 yarn startでも10倍以上の差があり、/hostdir がかなり遅い。
- 自身の環境では、dockerでホスト側を共有したvolumeの速度はwsl1の時相当になっているため非常に遅い（WSL2 の仮想マシンとして Docker サーバーが動くようになっている、wsl2 Ubuntuは動いていない）
- 自身のDocket desktop の設定では
  `General -> Use the WSL2 based engine` はチェックON（後述の画面キャプチャ参照）、
  `Resources -> WSL Integration` では Ubuntuが表示されていなかった（マイクロソフトストアからUbuntsを入れていない状態）
　なお、最新の自身の環境ではUbuntuがインストール失敗しないようになったため、Ubunts入れたが、Ubunts-20.04は有効にしていない（後述の画面キャプチャ参照）、

- 自身の設定をコマンドプロンプトで見ると
    - Ubunts 20.04 入れる前
    
    ```
    >wsl -l -v
    NAME                   STATE           VERSION
    * docker-desktop-data    Running         2
      docker-desktop         Running         2
    ```
    - Ubunts 20.04 入れた後

    ```
    wsl -l -v
    NAME                   STATE           VERSION
    * docker-desktop-data    Running         2
      docker-desktop         Running         2
      Ubuntu-20.04           Running         2
    ```

- Dockerの設定画面
     - `General -> Use the WSL2 based engine`
     -  <img width="50%" alt="14-01_docker.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/afce905f-04fa-ff1b-6c81-e47b576006ec.png">

     - `Resources -> WSL Integration` Ubunts-20.04は有効でない（無効）
     - <img width="50%" alt="14_02_docker_resources.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/c1d7e25c-07b4-aa9e-b58a-00bda18b89a4.png">

### WSL2でのコンテナ－ホスト間の速度改善 ~~を行うには（速くなるのか不明）~~ できなかった
- https://docs.docker.com/docker-for-windows/wsl/#best-practices ,https://docs.docker.jp/docker-for-windows/wsl.html の公式をみると、

```
Performance is much higher when files are bind-mounted from the Linux filesystem, 
rather than remoted from the Windows host. 
Therefore avoid docker run -v /mnt/c/users:/users (where /mnt/c is mounted from Windows).
```
とあり、windows側の`/mnt/c/users` を `/users` にマウントするのは避けるって書かれてるな。
wsl2 Ubuntu内のファイルを使うしかないんだろうか・・・・

- 以下、考えてみたがダメかな
- 先に記載の、 `Resources -> WSL Integration` Ubunts-20.04を有効にする
- wsl2 Ubuntuから見えるパスを使うようにする
    - 例えば、`/mnt/c/usr/aws-tutorial` のようなパス（wsl2がホスト側のCドライブの`c:\\usr\aws-tutorial`をよしなにやってくれる）
- 参考 
    - ![15_ubuntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/b9974ed3-b920-8bf5-ce60-67f7f507c83f.png)

- wsl2経由にすると
おそらく
`コンテナ -> ホストOS ->  Windowsの場所`
というアクセスから
`コンテナ -> WSL2 Ubunts  -> WSL2から見たWindowsの場所` に変えればアクセス速度は~~少しは速くなると想定される（Linux、Ubunts等での通信になり、ホストOSを介さない）~~ 速くならない

- Windowsからwsl2 Ubuntuへのアクセスは、`\\wsl$\Ubuntu-20.04\home\` のようにアクセスできる
    - PowerShellから`wsl$` へのアクセス例
![16-wsl2-ps_ubuntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/15800795-8e60-a25b-2f3c-c74dff32e17e.png)
    - Windowsから WSL2 Ubunts内のファイルをVSCodeで開く（Ubuntu内で `code .` コマンド実行で良い） 、左下が「WSL:Ubuntu-20.04」になっていれば開けている
![16-wsl2-vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/83a86663-520b-1acb-62c0-e4ae1397ef76.png)

## （番外編）docker-composeを使うようにした場合

- リモートコンテナ利用でdocker-composeを使うように改変したもの、https://github.com/ssugimoto/aws-amplify-sns-workshop-in-vscode/tree/feature/use-docker-compose-forWindows
    - featureブランチに入れてます。forkしていますが、あくまでもサンプルです。

- Windows向けで試したのみ、Mac,Linuxで動くかは不明です。
- docker-composeのvolumesで、Windows側の環境変数指定ができず、`.aws` , `.ssh` 指定が絶対パスになり個人ごとに依存するため、カレントディレクトリに、`aws`, `ssh` のディレクトリを用意し、そのディレクトリをマウントするようにしてみた
- コンテナが停止してしまうので、`command: /bin/sh -c "while sleep 2000; do :; done"` で対処した
- /hostdir をワーキングディレクトリにした、コンテナ内の`/workspaces`も使える
- docker コンテナ一覧では、どれなのか非常にわかりやすくなる、こんな感じに
<img width="50%" alt="2-01_docker_compose.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/9e03f692-9465-a1a3-3b9f-d4570ef2c6ff.png">

- amplify と nodeのバージョンアップした後のコンソール
<img width="50%" alt="2-02_VSCode.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1482752/9ef7d9cc-8c44-7ea7-ca58-edc5d21144b0.png">