VSCodeのDev Containersで開発環境構築のポイントをまとめてみた。

この記事は[朝日新聞社 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/asahi) の25日目の記事です。

新しいパソコンをゲットしたあと、開発の実作業に入るまでの開発環境セットアップって思ったよりも時間がかかりますよね:grimacing:
開発環境のセットアップも楽しいですが、既存のプロジェクトの開発にささっと入りたいなんて時は、もどかしさを感じながらセットアップをすることとなります:rolling_eyes:

そんなとき、プロジェクトにDev Containersを導入しておくと、すぐに開発を始めることができます。

というわけで、今回はVSCodeのDev Containers環境について書いていこうと思います:fist:
なお、公式ドキュメントに書いてあることはリンクを貼っています。基本的な動作に関しては公式ドキュメントを参照してください。
本記事では、これ便利だった！みたいなポイントをまとめていきます:ghost:

## :point_right: 導入手順
基本的な導入手順は公式チュートリアルを読んで実施してください。
英語ですが、翻訳機能を使って読んでください:muscle:
→ [公式チュートリアル](https://code.visualstudio.com/docs/devcontainers/tutorial)

## :robot: Dev Containers導入Tips
それでは実際に使ってわかったポイントを書いていきます。
## :memo: エディタはVSCodeだけなの？
#### :computer:　Vimとか
Devcontainerは基本的にVSCodeの機能です。が、CLI環境でも使えるようなツールがあります。
→[devcontainers/cli](https://github.com/devcontainers/cli)

```
npm install -g @devcontainers/cli
```
npmでインストールすることができます。
`.devcontainer`ディレクトリがある場所で上記コマンドを実行することでdevcontainerを起動することが可能です。ただ、環境を停止するコマンドはないので、自身で停止させる必要があります:frowning2:

開発するときはこの２つの方法がありそうです。
* バインドマウントしたファイルをホスト側から中身をいじる。
* Docker execで開発環境にはいって、中身をいじる。
    * ちなみに`devcontainer exec`コマンドでコンテナ内に入ってコマンドを打ってもレスポンスがなかったです:cry:

VSCodeを使ったときほどのメリットがあるようには感じられなかったのですが、私自身CLIツールで開発をしたことがないので、Vim、Emacs使ってる方にはぜひ使ってみて頂いて感想を頂きたいです🙇🏻

#### :rocket:JetBrains製IDE
現状 JetBrains が提供しているコンテナで開発できる系ツールは以下の２つです。
* [JetBrains Gateway](https://www.jetbrains.com/ja-jp/remote-development/gateway/)
* [Fleet](https://www.jetbrains.com/ja-jp/fleet/)

[devcontainers/cli](https://github.com/devcontainers/cli) を使って、devcontainer.jsonの一部を生かしつつコンテナを起動し、上記IDE、エディタで開発できそうです。

##### JetBrains Gateway
JetBrans Gatewayを使う際に課題となりそうな点は下記の通りです。

* 現状ローカルコンテナへの接続方法がSSHなので Dockerfile にSSHをインストールしないといけない:cry:
* M1 Mac やとIDE Server のインストールに失敗する。
* x86_64 でビルドしたコンテナやと Java プロジェクトのビルドめっちゃ遅かったりした。
参考：[IntelliJ IDEA リモート開発環境の自動構築を試してみよう](https://blog.jetbrains.com/ja/2022/02/15/automate-intellij-remotedevenv/)

VSCodeの機能を無理やり使う感じなので、ちょっと厳しそうな印象をうけました。

##### Fleet
JetBrans Gatewayを使う際に課題となりそうな点は下記の通りです。

* 起動済みのコンテナに対してSSHなしでも接続できた
* データベースやDockerなどの便利ツールはまだなさそう:cry:
* コードの補完とかはJetBrains製のエンジンらしい
* ただし料金体系は他IDEとは別になる予定

個人的にはJetBranins版VSCode感を感じているFleetですが、これならVSCode使えばいいかな？とも思いました。コード補完的な部分はJetBrains製のエンジンっぽいので、JetBrainsユーザーはFleetを視野にいれてもいいかもしれません。

##### つまり:thinking:
`devcontainer-cli`を使ってコンテナを起動し、（既存の）コンテナ開発環境に対して`Fleet`で開発するスタイルはよさそうです。でもFleet使うのであれば、VSCodeでもいいような気がしました。

## :file_folder:Gitの認証情報はホストマシンのものを使ってくれる。

gitの認証情報はDevcontainerが自動転送してくれます！
httpsかSSHキーかで挙動が変わるので注意してください。

### :zap:HTTPS
GitHub CLI または Git Credential Managerを使っていればホストの情報をコンテナ内に持っていってくれる。そうではない場合は、環境変数などでTOKENなどを渡す必要がある。

``` 例：devcontainer.json
# configでGITHUB_ACCESS_TOKENを登録する例
"postCreateCommand": "git config pull.rebase false && git config --global url.\"https://${GITHUB_ACCESS_TOKEN}:x-oauth-basic
# 環境変数を追加する
environment:
    - GITHUB_ACCESS_TOKEN
```
参考：https://code.visualstudio.com/docs/devcontainers/containers#_using-a-credential-helper

### :key: SSH

ホストの情報をコンテナに自動的に転送してくれます。
参考：https://code.visualstudio.com/docs/devcontainers/containers#_using-ssh-keys

### つまり３つの方法がある
1. ssh認証でクローンする
1. https認証でクローンし、devcontainer内でTOKENの設定を追加する
1. https認証でクローンし、GitHub CLI または Git Credential Managerで資格情報をコンテナにわたす

1が一番手軽。3が次に手軽。2はdevcontainerの記述が増える。
1でやるのをおすすめします。

## :hammer:Devcontainer.json起動時のcommandをどのタイミングで叩くか問題
devcontainer実行時にいろいろなタイミングでcommandを実行できます。
詳細はこちら→ [lifecycle-scripts](https://containers.dev/implementors/json_reference/#lifecycle-scripts)

この３つをよく使いました。
|Property  |Description  |
|---|---|
|`postCreateCommand`|コンテナ作成後、dotfiles や拡張機能のインストール前に実行される。コンテナ作成時の1回のみ実行される。|
|`postStartCommand`|VS Code Server 接続後に実行される。拡張機能以外のコンテナ設定が終わった後に実行される。リモート接続するたびに実行される。|
|`postAttachCommand`|postStartCommand の後に実行される。拡張機能のインストールと並列実行されている。リモート接続するたびに実行される。|

例えば`npm i`とか`npm start`とかをdevcontainer起動時に実行したいなら、上をうまく使って書くと良いと思います。
```
  "postCreateCommand": "npm install",
  "postStartCommand": "npm run dev",
```
こんな感じですかね。

## :wrench: settings.jsonについて
settings.jsonはVSCodeの設定を記述ファイルのことです。
DevContainerでは２つの設定方法があります。

* devcontainer.jsonに書く
* .vscode/settiings.jsonに書く

それぞれVSCodeの設定に反映されるが、反映される範囲が異なります。

①はコンテナ内VSCodeに対して行われる設定
②はコンテナ内VSCodeのワークスペースに対して行われる設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241035/77979f6a-c7d7-abd7-6a57-c15e33ce29e5.png)

上記の画像はVSCode内で設定を開いた画面(`⌘,`で開ける)。

* User
* Remote
* Workspace

と、3種類のタブがあります。

Userは、ユーザーが使っているパソコンにインストールされたVSCodeに反映されている設定。
Remoteは、`devcontainer.json`に書かれた設定。
Workspaceは、`.vecode/settings.json`に書かれた設定。

設定の優先度は右が高くなります。

状況によるとは思いますが、Workspaceで設定しておいたほうが、わかりやすくて良いような気がしました。

## :link: ポートフォワーディング設定を自動でしてくれる。
コンテナ内で何かしらのポートでアプリケーションを起動すると、VSCodeが自動的にポートフォワーディング設定をしてくれます！！
しかし、明示できる場合は明示しておいたほうがよいような気はします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241035/2e808743-b6c9-42b2-e6db-d129d2ed8479.png)

設定は下記の通りです。devcontainer.jsonに書きのようにポートフォワーディングするものを記述するだけです。
Doc: https://code.visualstudio.com/docs/remote/containers#_always-forwarding-a-port

# :bellhop: おしまい
Dev Containersを実際に使ってわかったポイントを5つ紹介してみました。
ローカルでVSCodeとDockerを用意してしまえば、すぐに開発に入れるDev Containersは非常に便利です。
細かい設定ぜひ使ってみてください。

なお、朝日新聞社では、技術職の中途採用を強化しています。
ご興味のある方は下記リンクから希望職種の募集ページに進んでください。
皆様からのご応募、お待ちしております！

https://www.asahishimbun-saiyou.com/information/career