Open59

GitHub Codespaces の使い方を調べる

snakasnaka
snakasnaka

https://docs.github.com/ja/codespaces/about-codespaces/codespaces-features

リポジトリ用に特別に構成された開発環境で作業できます。 そのプロジェクトで作業するために必要なすべてのツール、言語、構成が揃っています。

いわゆる「おま環」問題が無くなる

VS Code の codespace で作業する場合、Live Share を使ってチームの他のユーザーと共同作業できます。 「codespace での共同作業」を参照してください。

LiveShare でペアプロもできる

codespace からポートを転送し、URL を共有して、自分がアプリケーションで行った変更を pull request で送信する前に、チームメイトがそれらの変更を試すことができるようにします。

マージ・デプロイ通さなくてもアプリケーションの動作をチームメンバーと共有できる

snakasnaka

https://docs.github.com/ja/codespaces/about-codespaces/understanding-the-codespace-lifecycle

コードスペースの作成を高速化するために、リポジトリ管理者は GitHub Codespaces prebuilds を有効にすることができます。

プレビルドを活用すると Codespace の作成が高速化できる

実行中のコードスペースにのみCPUコストが発生します。 停止したコードスペースには、ストレージ・コストのみが発生します。

停止中でもストレージにコストがかかるのは注意

snakasnaka

開発コンテナの構成をカスタマイズする

https://docs.github.com/ja/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers

リポジトリ用に単一の開発コンテナー構成を定義したり、異なるブランチ用に異なる構成を定義したり、複数の構成を定義したりできます。複数の構成を利用できる場合、ユーザーは codespace を作成するときに好みの構成を選択できます。 ... (略) ... 構成の選択肢を作成することで、異なるチームが、実行する作業用に適切に設定された codespace で作業できるようになります。

求めてたものかもしれない

リンターのようなものは標準化して、すべてのユーザーにインストールするよう求めることが適切なので、devcontainer.json ファイルに含めることができます。 ユーザー インターフェイスのデコレーターやテーマなどは、devcontainer.json ファイルに含めるべきでない個人的な選択肢です。

メンバーで共有する設定を devcontainer.json に入れて、個人的な設定は入れない。

devcontainer.json ファイルは JSONC (コメント付きの JSON) 形式を使用して記述されます。 これにより、構成ファイル内にコメントを含めることができます。

JSONC めずらしい

Hidden comment
snakasnaka

ローカルで Dev Container を試す

Codespaces を触る前に、まずローカル(VS Code)の Dev Container の動作を確認してみる

https://zenn.dev/takayuu/articles/7469ca6285c962

snakasnaka

Open Folder in Container.. を選択して、先に作成したフォルダを指定すると .devcontainer/devcontainer.json を読み込んでコンテナが立ち上がった

ちょっとビルドに時間かかる

snakasnaka

ビルド失敗

[2025-05-26T22:37:34.707Z] Dockerfile-with-features:19
--------------------
  17 |     RUN yarn install
  18 |     
  19 | >>> COPY ../Gemfile ../Gemfile.lock ./
  20 |     RUN bundle install --path 'vendor/bundle'
  21 |     
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref e6d490eb-a9e3-419c-9add-b6e519e01e33::k126hrc6sq7su66czzr2pv632: "/Gemfile.lock": not found

Gemfile.lock が無い。あと yarn.lock

devcontainer の外でターミナル開いて以下を実行して Gemfile.lock, yarn.lock を作成する

bundle install
yarn

修正後に立ち上げ直すのは Reopen Container... (スクショ取り忘れた)

snakasnaka

git コマンドで 1Password の SSH キーを使う

まず、macOS 側の環境変数 SSH_AUTH_SOCK を設定するため ~/.bash_profile を編集

~/.bashrc
export SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock

OS再起動して、まずは以下のとおり環境変数が有効であることを確認

$ env | grep SSH
SSH_AUTH_SOCK=/Users/foo/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock

$ ssh -T git@github.com
Hi snaka! You've successfully authenticated, but GitHub does not provide shell access.

この状態で、devcontainer.json を編集

devcontainer.json
{
  "name": "Ruby",
  "build": {
    "dockerfile": "Dockerfile",
    "context": ".."
  },
  "workspaceFolder": "/workspace",
  "containerEnv": {
    // 【追加】dev container で 1Password の ssh キーを利用する設定
    "SSH_AUTH_SOCK": "/run/host-services/ssh-auth.sock"
  },
  "mounts": [
    "source=${localWorkspaceFolder},target=/workspace,type=bind",
    "source=${localWorkspaceFolderBasename}_node_modules,target=/workspace/node_modules,type=volume",
    "source=${localWorkspaceFolderBasename}_bundle,target=/workspace/vendor/bundle,type=volume",
    // 【追加】dev container で 1Password の ssh キーを利用する設定
    "source=/run/host-services/ssh-auth.sock,target=/run/host-services/ssh-auth.sock,type=bind"
  ]
}

コンテナ内のターミナルで 以下を実行してアクセスできるのを確認

$ ssh -T git@github.com
Hi snaka! You've successfully authenticated, but GitHub does not provide shell access.

上記のように変更したあと、コマンドパレットから Dev Container: Rebuild Container を実行してコンテナをビルドし直し (コンテナ入り直すだけでよかったかも?)

snakasnaka

ruby-lsp のインストールは失敗した

root@63875b763180:/workspace# bundle add ruby-lsp --group "development" --require false

[!] There was an error parsing `injected gems`: You cannot specify the same gem twice with different version requirements.
You specified: ruby-lsp (~> 0.23.23) and ruby-lsp (>= 0). Gem already added. Bundler cannot continue.

 #  from injected gems:1
 #  -------------------------------------------
 >  gem "ruby-lsp", ">= 0", :group => :development, :require => false
 #  -------------------------------------------

よくわからないので一旦スルー

snakasnaka

既存の Docker 開発環境を Codespace で稼働させてみる

普段、開発に利用している Dockerfile が Project Root に存在するとして、以下のように devcontainer.json を設定する。

  • Dockerfile は project root から見て docker/Dockerfile という path に配置されている
.devcontainer/devcontainer.json
{
  "name": "This is devcontainer name",
  "build": {
    "dockerfile": "../docker/Dockerfile",
    "context": "../docker"
  }
}

この修正を適当な Topic ブランチ立てて、GitHub に push する。
push したら Pull Request を作って、そこから Codespace を立ち上げる。

初回はビルドに数分かかる

snakasnaka

立ち上げ失敗してた

This codespace is currently running in recovery mode due to a container error.
1. Use Cmd/Ctrl + Shift + P -> "Codespaces: View Creation Log" to see full logs
2. Update your devcontainer configuration as needed
3. Use Cmd/Ctrl + Shift + P -> "Codespaces: Rebuild Container" to retry
4. For help, read more about custom configuration: https://aka.ms/ghcs-custom-configuration
snakasnaka

devcontainer.json の内容が最新の状態になっていないことが判明したので Command Palette から Codespaces: Rebuild Container を実行

snakasnaka

勘違い... Codespace 立ち上げた元のブランチの変更に自動的に追随するわけじゃないのか....

明示的に git pull する必要がある。そして初期の clone は shallow なので git pull の段階で多くの履歴が落ちてくる。

git pull が完了すると Rebuild を促される

無事に Rebuild 完了したら Codespace 環境が使えるようになった。

snakasnaka

🟩プライベートな Gem のリポジトリへのアクセスに失敗

bundle install で失敗。該当プロジェクトは private な gem のリポジトリにアクセスしているため、そこが失敗しているっぽい

ログ抜粋
Retrying `git clone --bare --no-hardlinks --quiet -- git@github.com:foo-org/bar ...

If this error persists you could try removing the cache directory '/workspaces/baz'
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
snakasnaka

https://docs.github.com/ja/enterprise-cloud@latest/codespaces/managing-your-codespaces/managing-repository-access-for-your-codespaces

追加または変更したカスタム アクセス許可は、変更がリポジトリにコミットされた後に作成された新しい codespace にのみ適用されます。 codespace 内からアクセス許可を追加または変更した場合、その codespace を再構築しても、これらのアクセス許可は現在のコードスペースには適用されません。

codespace を新しく作る必要があるのか

snakasnaka

codespace 作り直したが解消しなかった

https://docs.github.com/ja/codespaces/troubleshooting/troubleshooting-authentication-to-a-repository

codespace の GITHUB_TOKEN は、codespace を作成したリポジトリに対する読み取りおよび書き込みアクセス権を持つように構成されます。 既定では、このトークンは他のリポジトリにアクセスできません。 リポジトリを複製できない場合があります。または、複製したリポジトリにプッシュできません。

これが関係してるかも?

snakasnaka

private リポジトリへの追加のアクセス権の要求を devcontainer.json に追記した

devcontainer.json
{
  "name": "This is devcontainer name",
  "build": {
    "dockerfile": "../docker/Dockerfile",
    "context": "../docker"
  },
  "customizations": {
    "codespaces": {
      "repositories": {
        "my-organization/private-repo": {
          "permissions": {
            "contents": "read"
          }
        },
        // 他の private リポジトリも同様に記述する
      }
    }
  }
}

最初 typo してて設定が反映されてなかったが、 typo に気づいて修正したらアクセス許可を求めてくれるようになった。

snakasnaka

これまでの内容を参考に
devcontainer.json に環境変数の設定を追加した

devcontainer.json (抜粋)
  "remoteEnv": {
    "BUNDLE_GITHUB__COM": "x-access-token:${localEnv:GITHUB_TOKEN}"
  },
snakasnaka

とりあえず、ここまでの環境は立ち上がった。

Hidden comment
snakasnaka

既存の docker-compoer.yml を利用する

ローカル端末での開発では、 docker compose コマンドで環境を用意していて、そのための docker-compose.yml を用意していた。 docker-compose.yml では MySQL や Redis , Sidekiq などのアプリを動作させるために必要なサービスを立ち上げるようになっている。

それをそのまま codespace で使えると楽そうと考えた。

Dockerfile で立ち上げに成功したものを docker-compose.yml で立ち上げるように変更

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index ed60007330..6872ff53b2 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,9 +1,6 @@
 {
   "name": "This is devcontainer name",
-  "build": {
-    "dockerfile": "../docker/Dockerfile.development",
-    "context": "../docker"
-  },
+  "dockerComposeFile": "../docker-compose.yml",
+  "service": "app",
   "remoteEnv": {
     "BUNDLE_GITHUB__COM": "x-access-token:${localEnv:GITHUB_TOKEN}"
   },

snakasnaka

codespace 起動に失敗した...

[31203 ms] Stop: Run: docker compose --project-name ...(snip)... up -d
Outcome: success User: root WorkspaceFolder: /workspaces/campfire-2
devcontainer process exited with exit code 0
Container creation failed.

Creating recovery container.
Creating container...

Container creation failed としか出てこなくて原因がわからない...

snakasnaka

あれ?見逃してたか?

Error response from daemon: failed to mkdir /var/lib/docker/volumes/campfire-2_bundle-data-volume/_data/bin: mkdir /var/lib/docker/volumes/campfire-2_bundle-data-volume/_data/bin: file exists

と思って Codespace 作り直してみたが、このエラー自体は解消しても Container creation failed は解消してなかった。

snakasnaka

rubygems.org を Codespace で立ち上げてみる

参考のために、既存のリポジトリで Dev Container の設定がある、かつ、 Rails を利用している物を探す。
path:devcontainer.json dockerComposeFile rails で検索してみたら rubygems.org がヒットした

https://github.com/rubygems/rubygems.org

このリポジトリで devcontainer.json の書き方を参考にしてみる

snakasnaka

devcontainer.json

devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
{
  "name": "RubyGems.org",
  "dockerComposeFile": [
    "docker-compose.yml",
    "../docker-compose.yml"
  ],
  "service": "rails-app",
  "runServices": [
    "db",
    "cache",
    "search",
    "toxiproxy",
    "selenium"
  ],
  "forwardPorts": [
    3000, // Rails
    11211, // Memcache
    9200, // Opensearch
    5432 // PostgreSQL
  ],
  //  .... 略
}
  • docker-compose.yml../docker-compose.yml の2つのファイルを使ってサービスを立ち上げている
  • runServices とあるので、 docker-compose.yml に記述されている service は立ち上がっているんだろう
  • forwardPorts でそれらの service の port がローカル端末に forward されていそう
snakasnaka

DB にクライアントからつないでみる
portForward されているのでローカル端末から

psql -h localhost -U postgres

見えている
しかし codespace のターミナルから見えないのはなぜだろう...

codespace で起動している service の管理ってどこからできるんだろう?
ローカルで docker compose している状況だと、ホスト側で docker ps とか Docker Desktop などでコンテナの状態を確認できたけど...
Codespces に接続している VS Code はそのコンテナの1つに接続しているので、ホスト側へのアクセス手段が無い...?

snakasnaka

と思ったら、ローカルでの docker compose の状態を思い出したらできた

psql -h db -U postgres

コンテナの中では docker-compose.yml で定義された service の名前がそれぞれ host 名として認識されている。よって上のように -h db とすることで接続できた

snakasnaka

データベースを rubygems_development に切り替える

\c rubygems_development 

テーブルの一覧を見る

\d

snakasnaka

devcontainer.json に修正を加えて、Rebuild して codespace を起動し直し。

devcontainer.json
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {},
    // "ghcr.io/rails/devcontainer/features/activestorage": {},
    "ghcr.io/rails/devcontainer/features/postgres-client": {},
    "ghcr.io/devcontainers-extra/features/apt-packages:1": {
      "packages": [
        "pkg-config"
      ]
    },
    // ↓この行を追加
    "ghcr.io/devcontainers/features/docker-outside-of-docker": {}
  },

docker ps コマンドが使えるようになった

snakasnaka

なんとなく Codespace での開発スタイルが見えてきた

snakasnaka

docker-in-docker で構築してみる

作業用のコンテナは標準的な環境 + docker-in-docker の環境 ( つまり docker が利用できる標準的 Linux 環境 ) を用意して、ローカルで docker を利用するのと同等の環境を再現してみる。

Codespaces の標準イメージは以下

https://github.com/devcontainers/images/tree/main/src/universal

snakasnaka

どうやら docker-in-docker は不要そう。デフォルトのイメージに入っていた。

👋 Welcome to Codespaces! You are on our default image. 
   - It includes runtimes and tools for Python, Node.js, Docker, and more. See the full list here: https://aka.ms/ghcs-default-image
   - Want to use a custom image instead? Learn more here: https://aka.ms/configure-codespace

🔍 To explore VS Code to its fullest, search using the Command Palette (Cmd/Ctrl + Shift + P or F1).

📝 Edit away, run your app as usual, and we'll automatically make it available for you to access.
snakasnaka

📝 docker compose でコンテナに GITHUB_TOKEN 渡すために -e BUNDLE_GITHUB__COM する必要があった

snakasnaka

既存の Dockerfile, docker-compose.yml などを活かせるという点で、こちらの方法が楽ではあった。
意識する仮想環境の階層が深くなるのがあまり好きではないが....

snakasnaka

理想はこれだったが、これだと codespace という Docker 環境向けの構成をローカル用とは別で管理することになりそう...(知らないだけでうまいやり方はありそう)

snakasnaka

立ち上げたコンテナ内でさらに別リポジトリ(Frontend)を clone したい

詳細は省略するが、およその手順は以下のとおり

  1. devcontainer.json の customizations.codespaces.repositories に対象リポジトリを追加する
  2. .local などの git 管理対象外のディレクトリに移動
    a. .local のようなディレクトリがなければ、それを .gitignore に追加 & ディレクトリ作成
  3. 対象リポジトリを GitHub CLI で clone (認証情報とかGITHUB_TOKENでよしなにやってくれる) する
  4. 対象を立ち上げる
snakasnaka

prebuild で待ち時間を短縮したい

https://docs.github.com/ja/codespaces/prebuilding-your-codespaces/about-github-codespaces-prebuilds

Organization が所有するリポジトリの場合、GitHub Codespaces のリポジトリ レベルの設定は、GitHub Team および GitHub Enterprise プランの Organization で使用できます。 設定にアクセスするには、Organization またはその親 Enterprise が支払い方法を追加し、GitHub Codespaces の使用制限を設定する必要があります。

チームで使う場合は Organization 設定が必要そう

プレビルドの構成ワークフローが実行されると、GitHub により一時的な codespace が作成され、devcontainer.json ファイル内の任意の onCreateCommand および updateContentCommand コマンドまでの設定操作が実行されます。 プレビルドの作成時に postCreateCommand コマンドは実行されません。

onCreateCommand , updateContentCommand があるとよさそう

snakasnaka

onCreateCommand を用意する

prebuidl する・しないにかかわらずあると良さそうなので用意しておく。