- はじめに
- GitHub Codespaces とは?
- 動作のイメージ
- DROBE の開発のセットアップの流れ
- devcontainer の作り方
- Codespaces の起動
- docker in docker
- Submodule
- Package について
- prebuild
- 使ってみてどうか?
- さいごに
はじめに
この記事では、弊社の開発環境を GitHub の Codespaces に構築した際の構成などをシェアします。
Codespaces を構築したモチベーションは、開発環境に関する以下のような課題に直面していたからです。
- ⏳ 開発環境のセットアップに時間が掛かる
- 🤓 新しく参加される方がセットアップにハマった際に、既存メンバーによるサポートの負荷が割と高い
- 📑 セットアップのドキュメントを整備していくコストが高い (もし xxx なら yyy をしてください、など注釈が必要になってきて、書く方も読む方も複雑なものと向き合う必要がある)
- 💻 Linter や Formatter が IDE の Extension に依存していて、設定を合わせるのが微妙に面倒
- 👩💻 リモートであるがゆえに席に来てもらって開発中の画面を触ってもらう、などが出来ない (例えばアニメーションなど)
GitHub Codespaces を使う事で、このような悩みが解決可能だと考え、導入を検討し実際に開発環境としていれてみました。
GitHub Codespaces とは?
このブログを読むとだいたいわかります。
もちろん我々とは規模が全く違いますが、課題感などはとてもシンパシーが湧く内容で、かつそれをいかに解決していったのかというストーリーが単純に読み物として面白いです。またそうやって作られたものが GitHub の機能として提供されているかと思うと感慨深いものもあります。
Codespaces にご興味をお持ちの方は是非ご一読をおすすめします。
動作のイメージ
Codespaces は devcontainer という開発用のコンテナを GitHub 管理下に建てて、そこに VSCode やブラウザを接続して使います。
試してはいませんが GitHub の提供する cli 経由で ssh も可能との事です。
DROBE の開発のセットアップの流れ
devcontainer の作り方
それでは、devcontainer の作りかたを解説していきます。
repository の root に ./devcontainer
を作り devcontainer.json
を配置します。
devcontainer.json
は Codespaces の設定ファイルで、devcontainer の実態となる Dockerfile
を指定する事が多いです。
devcontainer.json
で指定された Dockerfile
は devcontainer の build に使われます。
.devcontainer/
├── Dockerfile
└── devcontainer.json
devcontainer.json
は以下のようなものになります
{
// devcontainer を作るのにつかう Dockerfile
"build": {
"dockerfile": "Dockerfile"
},
// 後で説明する Docker-in-Docker の設定
// ref. https://github.com/microsoft/vscode-dev-containers/blob/main/containers/docker-in-docker/README.md
"runArgs": ["--init", "--privileged"],
"mounts": ["source=dind-var-lib-docker,target=/var/lib/docker,type=volume"],
"overrideCommand": false,
// Visual studio code の Remote [Codespaces]-scoped settings の設定 codespace
"settings": {
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
],
// prebuild
"onCreateCommand": "cd /workspaces/drobe && sh script/codespace/prebuilt.sh", // 後で説明する prebuild される時に実行されるコマンド
// post build
"postCreateCommand": "service redis-server start" // devcontainer が作られた後に実行されるコマンド
}
Dockerfile
は devcontainer を作るたびに作られるので、先に必要なセットアップが終わったものを準備しておき、ここではそのコンテナを pull するだけにしています
FROM ghcr.io/{org-name}/{repo-name}/{dev-container-name}:{hash}
Codespaces の起動
./devcontainer
をセットアップした上で repository の Code
ボタンから Codespaces を起動できるようになります。
- 緑色の「 <> Code ∨」ボタンを押し、モーダル内の「Codespaces」タブを選択し、ボタンのプルダウンから「Configure and create codespace」を選択してボタンをクリックします。
- ブランチとマシンタイプを選択します
- setting up your codespace という画面が表示されるので、そのまま待ちます (ここで vscode desktop をクリックしてローカルの vscode を起動しても大丈夫です)
- セットアップが完了すると、自動的に新規作成された codespace に接続した Visual Studio Code for web が開きます
- Terminal が使えるようになるので、セットアップに必要なコマンドなどを叩けます
docker-compose
などでアプリケーション群を立ち上げると、自動的にポートが開放されます TERMINALの横のPORTSタブを開くと、各アプリケーション用に開かれたポートと、そこへアクセスするためのURLが表示されます Local AddressのURLにアクセスすると実際にcodespaceで稼働しているアプリケーションを見ることが出来ます
docker in docker
DROBE は開発に docker-compose を使っているため、Codespaces 環境では docker-in-docker を使う事になります。
弊社の場合の Dockerfile
は MS の docker-in-docker 用の script を使って以下のように作っています
FROM php:8.0.7-cli
~ 中略 ~
# [Option] Install zsh
ARG INSTALL_ZSH="false"
# [Option] Upgrade OS packages to their latest versions
ARG UPGRADE_PACKAGES="false"
# [Option] Enable non-root Docker access in container
ARG ENABLE_NONROOT_DOCKER="false"
# [Option] Use the OSS Moby Engine instead of the licensed Docker Engine
ARG USE_MOBY="false"
# Install needed packages and setup non-root user. Use a separate RUN statement to add your
# own dependencies. A user of "automatic" attempts to reuse an user ID if one already exists.
ARG USERNAME=none
ARG USER_UID=0
ARG USER_GID=$USER_UID
# Copy library scripts to execute
COPY library-scripts/*.sh library-scripts/*.env /tmp/library-scripts/
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
&& apt-get purge -y imagemagick imagemagick-6-common \
# Install common packages, non-root user
&& bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
# Use Docker script from script library to set things up
RUN bash /tmp/library-scripts/docker-in-docker-debian.sh "${ENABLE_NONROOT_DOCKER}" "${USERNAME}" "${USE_MOBY}" \
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
~ 略 ~
Dockerfile
内部で叩かれている common-debian.sh と docker-in-docker-debian.sh は MS 公式の devcontainer の定義 repo から拝借しています
また、上記は設定にあたってコチラのブログを大変参考にさせていただきました (この場を借りてお礼させて頂ければと思います)
Submodule
Repository によっては submodule を利用しているものもあると思いますが、codespace で submodule を使う場合は注意が必要です。具体的には .gitmodules
の submodule の url は https
から始まるものにしておく必要がありました。弊社環境においてはssh
で接続する git@github.com
から始まる url では git submodule update --init
に失敗してしまいました。(2022/06 現在)
Package について
Codespace 内部で github container registry に保存された package を使いたい、というニーズはあるかとおもいます
その場合は package の setting に対して codespace からの接続を許可する必要があります
prebuild
ここまでで Codespace の利用の設定は完了で、実際に開発を始める事が可能です。 ただしこの状態だと、Codespace でインスタンスを作る度に (Dockerfile に書いていない) セットアップのコマンドなどは自分で叩く必要があります。 それでも開発環境としては十分に使い勝手は良いと言えると思いますが、もっと起動を高速化したくなるのが人情というものです。
そこで利用できるのが prebuild という仕組みです。 prebuild を利用すると、devcontainer に対してさらにセットアップのコマンドなどを実行したものをベースの環境として開発を始められるようになります。
設定は簡単で、まずは prebuild 時に実行したいコマンドを devcontainer.json
の onCreateCommand
に指定します
"onCreateCommand": "sh /workspaces/drobe/script/codespace/prebuilt.sh"
onCreateCommand
を書いたら repository の settings から Codespaces → Set up prebuild をクリックします。
Prebuild の設定では Branch を選んで Region と Trigger を選択します。
以降、選択した branch に push がある度に GitHub actions が自動で走り (ここでは github actions 用 workflow の yml を用意する必要はありません) devcontainer の build → onCreateCommand の実行が終わったものを prebuild image として保存してくれます。
この prebuild を設定する事で、開発開始までの時間は劇的に短縮されます。
弊社の場合は setup の script が 30 分くらい掛かってしまっており、 git clone から開発を開始できるまで、少なくとも 1 時間くらい、ハマったりすると半日以上掛かる事もよくありました。prebuild 無しの codespaces を利用すると、コマンドが途中でこけてハマるというような事はなくなりましたが、それでも新しい環境を用意するのに 30 分掛かっていました。
prebuild を利用した codespace 環境を手に入れてからは、開発に初めて参加する人でも数分以内にはセットアップが完全に終わった新しい環境を用意することが出来るようになりました。
使ってみてどうか?
使ってみた率直な感想としては、単純に最高だなと思っています。数分で確実に新しい環境が手に入るので、ブランチ毎に環境を準備するなども可能で、開発の幅も広がりそうだと感じています。ローカルのマシンで docker を走らせなくて良いというのもスッキリして快適さを感じます。
また、元々持っていた課題に対してはどうだったかというと以下のように全ての課題を解決する事が出来ました 🎊
- ⏳ 開発環境のセットアップに時間が掛かる
- 🤓 新しく参加される方がセットアップにハマった際に、既存メンバーによるサポートが割と負荷が掛かる
- 📑 セットアップのドキュメントを整備していくコストが高い (もし xxx なら yyy をしてください、など注釈が必要になってきて、書く方も読む方も複雑化なものと向き合う必要がある)
- 💻 Linter や Formatter が Visual studio code の Extension に依存していて、設定を合わせるのが微妙に面倒
- 👩💻 リモートであるがゆえに席に来てもらって開発中の画面を触ってもらう、などが出来ない (アニメーションなど)
✅ 起動は 30 秒 ~ 数分くらいでサッと環境が立ち上がります。(若干 docker の pull 時間に依存して長くなる時がありました)
✅ 今のところ確実に誰でも動作しています
✅ 必要なツールなどがあれば devcontainer をメンテする、という方針にかわりました
✅ Linter や Formatter を含めて codespaces に設定出来るので迷わないし自分で設定する必要がない
✅ 自分の画面を github の organization のメンバーに好きな時にシェアできる
さいごに
DROBE では一緒にコードを書く仲間を募集しています!
Codespace 気になったからちょっと使ってみたい、とかもウェルカムですので、気になった方は是非お気軽にお知らせください!