VS Code オンライン版「code-server」 を AWS Lightsail に構築（マルチユーザー対応）

## 本記事の内容
- VS Codeのオンライン版「code-server」をAWS Lightsailに構築し、ブラウザがあればどこでも開発できる環境を作る。
- 下記設定を行う。（今後追加予定）
  - マルチユーザー対応
  - 拡張機能のインストールと設定
  - Node.jsのインストール

※本記事は、code-serverやDockerを学習しながら書いています。
もっと良い設定や方法がありましたら、コメントいただけると嬉しいです。

## 前提条件
- Lightsailインスタンス（Linux）を作成済み。
- Docker、Docker Composeを導入済み。

本記事は、Lightsailの3.5ドルプラン、CentOS バージョン 7.9.2009 で作成。
※その後、5ドルプラン（メモリ1GB）にアップグレード。
メモリ512MBではスワップが大量に発生し、操作レスポンスが落ちたり、npmでのパッケージインストール時にタイムアウトが発生するなど、実用には厳しかったです。
公式ドキュメントでは2コアCPU、メモリ1GB以上が推奨されています。（Lightsailの2CPUは、20ドルプランより）
[code-server/guide.md at v3.8.0 · cdr/code-server · GitHub](https://github.com/cdr/code-server/blob/v3.8.0/doc/guide.md)

構築手順は下記記事にまとめています。

[AWS Lightsail 入門1 インスタンス作成](https://qiita.com/s8ta/items/fd274b05b083bcf36dba)
[AWS Lightsail 入門2 SSH接続（RLogin）](https://qiita.com/s8ta/items/688aa803d2874feff82c)
[AWS Lightsail 入門3 基本設定（管理画面）](https://qiita.com/s8ta/items/d3e475c8f26580c9ce5e)
[AWS Lightsail 入門4 基本設定（CentOS 7）](https://qiita.com/s8ta/items/696fc68b27b91128251a)
[Docker 簡単インストール手順（CentOS）](https://qiita.com/s8ta/items/27cf3f7b47e3963f21db)

## とりあえず動かしてみる
Docker Hubより、code-server最新版のイメージを取得して起動する。

```
$ docker run -it --name code-server -p 80:8080 codercom/code-server:latest
```

- `-p 80:8080`で、ホストOSの80番ポートをコンテナ内のcode-serverが使用する8080番ポートに紐づける。

下記メッセージが表示され、code-serverが起動する。

```
 info  Wrote default config file to ~/.config/code-server/config.yaml
 info  code-server 3.8.0 c4610f7829701aadb045d450013b84491c30580d
 info  Using user-data-dir ~/.local/share/code-server
 info  Using config file ~/.config/code-server/config.yaml
 info  HTTP server listening on http://0.0.0.0:8080 
 info    - Authentication is enabled
 info      - Using password from ~/.config/code-server/config.yaml
 info    - Not serving HTTPS
```

ブラウザから`http://インスタンスのパブリックIP`にアクセスすると、code-serverのログイン画面が表示される。
<img width="50%" alt="code-server-lightsail-01-001.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/00030058-d45a-ff16-9210-2539a4f927cd.png">

コンテナ内の`config.yaml`に記述されたパスワードを確認し、ログイン画面に入力する。（code-serverを起動したターミナルは待機状態なので、別のターミナルで確認する）

```
$ docker exec code-server cat /home/coder/.config/code-server/config.yaml
bind-addr: 127.0.0.1:8080
auth: password
password: ここにパスワードが表示される
cert: false
```

VS Codeと同様の画面がブラウザ上で開く。
<img alt="code-server-lightsail-01-002.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/1695e5f8-9e49-b2a7-5ff6-a6c86d28d967.png">

code-serverを起動したターミナルで、`Ctrl+C`を入力すると終了する。

## 設定方針
本記事では、次の方針でcode-serverを設定する。

### マルチユーザー対応
- ホストOS上に複数のcode-serverコンテナを起動し、複数ユーザーでの利用を可能にする。
- 各ユーザーは、ブラウザからのアクセス時に自身に割り当てられたポート番号を指定し、自分専用のcode-serverに接続する。
- ホストOS側に各ユーザーを作成。ホームディレクトリ内に作成した「projects」ディレクトリをコンテナにマウントする。  
（code-server上で「projects」内に作成したファイルは、ホストOS上に保存される。）
- ユーザーの追加は、スクリプト実行とdocker-compose.ymlへの少しの追記で簡単に行えるようにする。

### 拡張機能のインストールと設定
- 拡張機能のインストールと基本設定を行ったDockerイメージを作成する。
- ユーザーの追加時、設定済みのエディタをすぐに用意できる。
- ユーザーがcode-server上で拡張機能のインストールや設定変更を行うことも可能だが、非推奨とする。  
※ホストOSに保存しないため、コンテナ削除時に消失する。  
※必要な拡張機能・設定はDockerイメージに含め、ユーザー間の環境差異を減らすことでトラブルを避ける。

### Node.jsのインストール
- DockerイメージにNode.js（LTS版）をインストールし、code-server上で使用できるようにする。

※複数バージョンの切替方法は要検討。（コンテナを分割する、Nodeバージョン管理ツールを導入するなど）

## 設定手順

### 1. ディレクトリ・ファイルの作成
サーバーの任意の場所に、下記ディレクトリ・ファイルを作成する。
（本記事では、/home/centosに作成）

PC上で作成後、RLoginのファイル転送機能でまとめてアップロードすると簡単。

```
$ tree /home/centos
/home/centos
└── code-server
    ├── code-server
    │   ├── Dockerfile
    │   └── files
    │       ├── config.yaml
    │       └── settings.json
    ├── docker-compose.yml
    └── user-add.sh

3 directories, 5 files
```

#### Dockerfile
code-serverのDockerイメージを作成するための定義。

```dockerfile:code-server/Dockerfile
FROM codercom/code-server:3.8.0

USER root

# Node.js（LTS）リポジトリ追加
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -

# パッケージインストール
RUN apt-get update && apt-get install -y --no-install-recommends \
    nodejs \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

# npm更新
RUN npm install -g --no-progress npm

# タイムゾーン設定（日本時間）
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

USER coder

# 拡張機能インストール
# Japanese Language Pack for Visual Studio Code
RUN code-server --install-extension ms-ceintl.vscode-language-pack-ja
RUN echo '{ "locale": "ja" }' > .local/share/code-server/User/argv.json

# 設定ファイルコピー
# サーバー設定
COPY --chown=coder:coder files/config.yaml /home/coder/.config/code-server/

# エディタ設定
COPY --chown=coder:coder files/settings.json /home/coder/.local/share/code-server/User/

# code-server起動
# ベースイメージのENTRYPOINT引数 "--bind-addr" を削除し、config.yamlの値を有効化
ENTRYPOINT ["/usr/bin/entrypoint.sh", "."]

```

- 必要に応じて、パッケージや拡張機能を追加する。
- 拡張機能は`RUN code-server --install-extension 拡張機能ID`でインストール可能。

拡張機能IDは、VS Codeで拡張機能を検索・表示した際に右上に表示される。
<img width="80%" alt="code-server-lightsail-01-003.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/55177cfb-1ce6-e94e-1847-84a361d73c4f.png">

#### config.yaml
code-serverの設定。
[password]は任意の値を記述。
（全ユーザー共通の初期パスワード）

```yaml:code-server/files/config.yaml
bind-addr: 0.0.0.0:8443
auth: password
password: default-password
cert: true

```

#### settings.json
エディタの設定。内容は任意。（基本的にはVS Codeのsettings.jsonと同様）
本設定がDockerイメージに書き込まれ、全ユーザーのデフォルト設定となる。

```json:code-server/files/settings.json
{
  "editor.renderWhitespace": "boundary",
  "editor.tabSize": 2,
  "editor.wordWrap": "on",
  "files.eol": "\n",
  "files.insertFinalNewline": true,
  "files.trimTrailingWhitespace": true,
  "telemetry.enableTelemetry": false,
  "terminal.integrated.shell.linux": "/bin/bash",
  "workbench.colorTheme": "Default Dark+"
}

```

#### docker-compose.yml
各ユーザーのcode-serverコンテナをまとめて管理するための設定。
下記例では2つのユーザー（user1とuser2）を定義している。

- ファイル内の全てのuser1、user2は、任意のユーザー名に置換。
- ports: ホスト側のポートを18443、28443など、重複しない値に設定。（コンテナ側は8443固定）
- user: 対象ユーザーのホストOS上でのUID:GIDを指定。  
UIDとGIDは`id ユーザー名`で確認。（「2. ユーザー作成」の後に記述）

```yaml:docker-compose.yml
version: '3'
services:
  user1:
    ports:
      - 18443:8443
    user: 1001:1001
    volumes:
      - /home/user1/projects:/home/coder/projects
    image: code-server
    build: ./code-server
    restart: unless-stopped
  user2:
    ports:
      - 28443:8443
    user: 1002:1002
    volumes:
      - /home/user2/projects:/home/coder/projects
    image: code-server
    build: ./code-server
    restart: unless-stopped
```

#### user-add.sh
ホストOS上にユーザーを作成し、ホームディレクトリにプロジェクト格納ディレクトリを作成するスクリプト。

```bash:user-add.sh
#!/bin/bash

# 引数１（ユーザー名）
user=$1
if [ -z "${user}" ]; then
  echo '引数１（ユーザー名）を指定してください。'　
  exit 1
fi

# ユーザー存在チェック
id ${user} > /dev/null 2>&1
if [ $? -ne 0 ]; then

  # ユーザー作成（存在しない場合）
  useradd ${user}
fi

# ディレクトリ作成
# プロジェクト
sudo -u ${user} mkdir -p "/home/${user}/projects"

```

### 2. ユーザー作成
ホストOS上に、ユーザーとプロジェクト格納ディレクトリを作成する。
code-serverディレクトリに移動し、下記コマンドを実行。

```
$ chmod +x user-add.sh
$ sudo ./user-add.sh ユーザー名
```

今回の例では下記コマンドを実行

```
$ chmod +x user-add.sh
$ sudo ./user-add.sh user1
$ sudo ./user-add.sh user2
```

### 3. code-server起動
code-serverディレクトリで、下記コマンド実行。

```
$ docker-compose up -d
```

正常に起動すると、以下のようになる。

```
$ docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                               NAMES
dd7276089a47   code-server   "/usr/bin/entrypoint…"   42 seconds ago   Up 40 seconds   8080/tcp, 0.0.0.0:18443->8443/tcp   code-server_user1_1
158e47ed67a4   code-server   "/usr/bin/entrypoint…"   42 seconds ago   Up 40 seconds   8080/tcp, 0.0.0.0:28443->8443/tcp   code-server_user2_1
```

### 4. Lightsailのファイアウォール設定
code-serverのポート（今回は18443と28443）に対して、外部から接続できるようにする。
Lightsail管理画面よりインスタンスを選択後、[ネットワーキング]タブ > [IPv4 ファイアウォール]内の[ルールを追加]を選択。
下記項目を入力後、[作成]を選択。

- ポートまたは範囲: 18443
- IP アドレスに制限する: チェック
- 送信元IPアドレス: 対象ユーザーのグローバルIP  
※未指定の場合、世界中のどこからでも接続できる状態になってしまうので、必ず設定する。

<img width="80%" alt="code-server-lightsail-01-004.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/9bf4970e-a085-840b-a237-e7a318206977.png">

他のユーザーのポート（28443など）も同様に設定する。

## 各ユーザーの利用開始手順

### 1. code-serverへの接続
ブラウザから`https://インスタンスのパブリックIP:ユーザー用ポート番号`にアクセスし、config.yamlで指定したパスワードを入力。
日本語化など、設定が反映された画面が表示される。

※SSL接続に自己署名証明書を使用しているため、警告が表示される場合がある。

<img alt="code-server-lightsail-01-005.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/ca7f47f3-4998-f312-137c-7f3bb22021f3.png">

### 2. PWA（プログレッシブ ウェブアプリ）としてインストール
Chromeのアドレスバー右側にある[code-server をインストールします]を選択。
<img width="30%" alt="code-server-lightsail-01-006.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/b86c4279-5dd8-c643-1f1f-88c8913b7741.png">

アドレスバーなどが非表示になり、VS Codeに近い見た目になる。
また、スタートメニューやデスクトップに追加され、簡単に起動できるようになる。
<img width="40%" alt="code-server-lightsail-01-007.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010477/6b1966af-462c-bd6e-271d-86b484d74c2b.png">

## code-serverの停止方法
code-serverディレクトリで、下記コマンド実行。

```
$ docker-compose stop
```

## パスワードの変更方法

1. ブラウザよりcode-serverに接続。（対象ユーザーのポート）
2. `Ctrl+O`を入力し、ファイル`/home/coder/.config/code-server/config.yaml`を開く。
3. [password]を任意のパスワードに変更。
4. `Ctrl+@`でターミナルを開き、コマンド`killall node`を実行。（code-server以外に起動したnodeがある場合は注意）
5. 再接続し、新しいパスワードを入力。

## まとめ
Lightsail上にcode-serverを構築し、複数のユーザーで使用するための手順を紹介しました。
今後、この環境で実際に開発し、課題や便利な設定などがあれば随時更新していきたいと思います。

## 参考
[code-server 構築の茨の道と、その近道](https://qiita.com/cognitom/items/6d8af8a71552ec9c6212)

上記記事で勉強させていただきました。
ありがとうございます。