1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#165 CursorのDevContainerでGitを使う際の設定例

Posted at

はじめに

VSCodeやCursorの拡張機能であるDev Containersは、プロジェクトごとに独立した開発環境をコンテナとして構築できる非常に便利な機能であり、Dev Containersを利用することで開発者毎の環境に左右されることなく、開発環境のセットアップが非常に容易になります。
そんな便利なツールであるDev Containersですが、CursorでDevContainer環境をセッティングしている際に、ホストマシンのSSH鍵がコンテナに自動転送されない という事象に遭遇しました。


本記事ではこの問題を回避しながら、開発者毎の環境に左右されない形でのセットアップについて共有します。

事象について

事象に遭遇後、改めて VSCodeのDev Containers ドキュメント を確認すると、ホスト上でssh-agentが設定されていれば自動的にコンテナ内にssh-agentが転送されるとの記載がありました。
実際、CursorではなくVSCodeでDev Containersを立ち上げ同様の環境を作ってみた所、意図した通りにssh-agentが転送されていることが確認できます。
しかし、CurosrのDev Containersを立ち上げるとssh-agentの自動転送が行われていませんでした。


そこで、そもそも各開発者にssh設定を強制する事に関しても積極的ではなかったというのもあり、自動転送のアプローチは諦めて別の手段を模索することにしました。


※ Microsoft製の拡張機能がCursor等のFork版エディタで使用できなくなっており、Cursorで使用されているDev ContainersはVSCodeで配信されているDev Containersとは機能に差異があるようです。

実現したいこと

以下の状態を目指します。

  1. コンテナ内での git clone , pull , push といった操作を、SSHキーの有無を意識せずに行えるようにする。
  2. git@github.com:... のようなSSH形式のリモートURLを、Gitコマンド実行時に自動で https://github.com/... のHTTPS形式に変換する。
  3. ホスト環境のGit設定には影響を与えずにDev Containers利用時のみ、この変換を適用する。

DockerfileでのHTTPS化

このアプローチの鍵となるのが、コンテナをビルドする際の Dockerfile に追記するGitの設定です。


以下は、実際に利用している Dockerfile の一部です。

# ... (前段の処理は省略) ...

# Git : HTTPS化とalias設定
ARG GIT_NAME
ARG GIT_EMAIL
RUN git config --global user.name $GIT_NAME \
    && git config --global user.email $GIT_EMAIL \
    && git config --global --add url."https://github.com/".insteadOf git@github.com: \
    && git config --global --add url."https://github.com/".insteadOf ssh://git@github.com

# ... (後段の処理は省略) ...

この設定の中で最も重要なのが、以下の2行です。

git config --global --add url."https://github.com/".insteadOf git@github.com:
git config --global --add url."https://github.com/".insteadOf ssh://git@github.com

これはGitの url.<base>.insteadOf という機能を利用した設定です。
この設定により、git@github.com: で始まるURLに対するすべてのGit操作は、代わりにhttps://github.com/ をベースとするURLに対して実行されるようになります。


内部的にURLを書き換えてから通信を行うため、origin に登録されているリモートURLをSSH形式のまま変更する必要がありません。
コンテナ内のGitがプロトコルを変換してくれるため、開発者はSSHかHTTPSかを意識せずに利用できます。


また、user.nameuser.email もコンテナビルド時に引数( args )として渡すことで、コンテナ内でのコミット者情報が正しく設定されるようにしています。
これらの引数は、 docker-compose.yml ファイル経由で渡します。 .env ファイルで設定するようにすると良いでしょう。

docker-compose.yml
services:
  api:
    build:
      context: ..
      dockerfile: .docker/dockerfile/Dockerfile.local
      args:
        - GIT_NAME=${GIT_NAME}
        - GIT_EMAIL=${GIT_EMAIL}
# ... (以下省略) ...

Dev Containers設定の全体像

Dev Containersは、.devcontainer/devcontainer.json ファイルをエントリーポイントとして、Dockerコンテナを構築・起動します。

devcontainer.json
{
  "name": "example-api",
  "dockerComposeFile": [
    "../docker-compose.yml",
    "docker-compose.yml"
  ],
  "service": "api",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  // ... (以下省略) ...
}

上記の例はほぼデフォルトですが、プロジェクトルートの docker-compose.yml.devcontainer ディレクトリ内の docker-compose.yml を読み込み、api という名前のサービスを開発コンテナとして利用するよう設定されています。


そして、その api サービスが、先ほど解説したGitのHTTPS化設定を含む Dockerfile をビルドする。という流れになっています。

実際の動作確認

設定が完了したコンテナを起動し、ターミナルを開いてみましょう。

まず、リモートリポジトリのURLを確認します。

$ git remote -v
origin  https://github.com/xxx/example-api.git (fetch)
origin  https://github.com/xxx/example-api.git (push)

URLがHTTPS形式に変換されていることがわかります。しかし、この状態でgit pullfetchを実行しても、認証を行っていないためエディタ上で認証を求められるかと思います。
通常のケースでは以下画像のフローで進めることで認証が完了しますが、今回は別の手段として gh を使った方法についても紹介します。

※ 通常のケースでのフロー

  1. 未認証状態でgitの認証が必要な動作を行うと以下のようなダイアログが表示されます。
auth-flow1
2. [許可] を押下するとコードと共にGitHubへの認証画面へ進むダイアログが表示されます。 auth-flow1
3. 認証画面へ進むと、以下のような画面になるので前項で表示されたコードを入力し [Continue] を押下します。 auth-flow1
4. 以下の画面が表示されたら認証は完了です。 auth-flow1

ghを使った認証設定

まずはDevContainer内で gh を使えるようにするために以下の設定を devcontainer.json に追記します。

devcontainer.json
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },

上記設定後、DevContainerを再ビルドすることでDevContainer内で gh コマンドが使えるようになります。
使えるようになったら、以下のコマンドを実行することで通常フローの③と同様に、ブラウザからの認証フローに進むことができます。

gh auth login --hostname github.com --git-protocol https --web

私個人としては、エディタからの認証フローに頼ってしまうと、開発者の環境によって思いもよらぬトラブルなどが生じる可能性があるので、マニュアルでの対応フローとして gh コマンドを使えるようにしておくのが良いと思います。
また、gh は今回のような用途だけでなくPRの確認などにも役立つので導入しておいて損はないと思っています。

引用

# GitHub CLI について
GitHub CLI は、すべての作業を 1 か所で行うことができるように、pull request、issues、GitHub Actions などの GitHub 機能をターミナルに集めたコマンドライン ツールです。

おまけ: 開発体験を向上させる設定

本プロジェクトのDockerfileには、GitのHTTPS化以外にも、コンテナでの開発を快適にするためのいくつかの工夫が施されています。ここではその一部をご紹介します。

1. ホストとの権限問題を解決するユーザー設定

基本的には devcontiner.json に以下の記述をすることで、自動的にホストのユーザー情報でコンテナ内の指定ユーザー情報を上書きするような挙動になります。

devcontainer.json
"remoteUser": "dev-user"

しかし、上記の設定をするにはコンテナ内にあらかじめユーザーを作っておく必要があることがある点から、ある程度明示的に適切なUIDとGIDを設定したユーザーを作っておくのが安全かと思います。


以下の設定でコンテナ内にホストと同じUID/GIDを持つユーザーを作成しています。

ARG USERNAME=dev-user
ARG HOST_UID
ARG HOST_GID

RUN groupadd --gid $HOST_GID $USERNAME \
    && useradd --uid $HOST_UID --gid $HOST_GID -m $USERNAME

# ... (中略) ...

USER $USERNAME
docker-compose.yml
services:
  api:
    build:
      context: ..
      dockerfile: .docker/dockerfile/Dockerfile.local
      args:
        - GIT_NAME=${GIT_NAME}
        - GIT_EMAIL=${GIT_EMAIL}
        - HOST_UID=${HOST_UID:-1000}
        - HOST_GID=${HOST_GID:-1000}
# ... (以下省略) ...
  • ARG HOST_UID, ARG HOST_GID: docker-compose.yml からホストマシンのユーザーIDとグループIDを受け取るためのビルド引数です。
  • useradd --uid $HOST_UID --gid $HOST_GID では、受け取ったIDを使ってコンテナ内にユーザーを作成します。

また、デフォルトとして各IDを 1000 とすることで、ホストのユーザー環境が一致する場合には特に .env などに特別設定すること無く開発することが可能です。
ホストのユーザー情報が違う場合にはこれらも併せて .env で管理することになります。


この設定により、コンテナ内で新しいファイルを作成したりしても、ホストマシンから見たときにファイルの所有者が自分自身となり、権限の問題を気にすることなくスムーズに作業を続けられます。

2. Gitブランチ表示付きのBashプロンプトカスタマイズ

コンテナのターミナルで作業している場合、今どのGitブランチにいるのかが分からなくなると不便です。
そこで、以下のような設定でBashのプロンプト(コマンド入力待ちの表示)をカスタマイズしています。

# Bash : 表示をカスタマイズ
RUN wget -qO /home/$USERNAME/.git-prompt.sh https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh && \
    echo 'source ~/.git-prompt.sh' >> /home/$USERNAME/.bashrc && \
    echo 'PROMPT_COMMAND='\''PS1="\[\033[1;32m\]\u\[\033[00m\]:\[\033[1;34m\]\w\[\033[1;31m\]\$(__git_ps1)\[\033[00m\] \$ "'\''' \
    >> /home/$USERNAME/.bashrc

この設定は3つのステップで構成されています。

  1. Git公式が配布している git-prompt.sh スクリプトをダウンロードします。これにはカレントディレクトリのGitステータス(ブランチ名など)を取得する便利な関数が含まれています。
  2. ~/.bashrcsource ~/.git-prompt.sh を追記し、ターミナル起動時にこのスクリプトが読み込まれるようにします。
  3. プロンプトの表示形式を定義する変数 PS1PROMPT_COMMAND 経由で設定します。\u(ユーザー名)や \w(カレントディレクトリ)といった特殊な変数に加えて、\$(__git_ps1) を記述することで、git-prompt.sh が提供する関数を呼び出し、現在のブランチ名をプロンプトに埋め込んでいます。

この設定により、ターミナルのプロンプトが ユーザー名:カレントディレクトリ(ブランチ名) $ のようにカラフルに表示され、作業効率が向上します。

出典

Gitの現在のブランチをプロンプトに表示するBash設定

終わりに

いかがでしたでしょうか。
今回は、git configurl.insteadOf 機能を利用して、CursorのDev ContainersにおけるSSHエージェント転送の問題を回避する方法を共有しました。
SSHキーの管理や転送設定が不要で、ホストのGit環境には影響を与えないという点で満足しています。
将来的にはアップデートでSSHエージェントの自動転送が行えるようになるかもしれませんが、それまではこのようなアプローチで運用していきたいと思います。
ここまで読んでいただきありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?