GitHub Codespaces上でdocker compose upしたい
はじめに
GitHub Codespaces便利ですよね。
.devcontainer
ディレクトリに色々ちゃんと整備しておくと安定した開発環境を多人数で共通で立ち上げられるところが便利です。
そんな便利なGitHub Codespaces上で docker-compose.yml
を使って docker compose up
して複数サービスを立ち上げたいと思ったことはありませんか?
(たとえばAPIサーバーとフロントエンドとDBと、などなど…)
GitHub Codespacesは実態はDockerコンテナ内なので、その内部で docker compose up
するのは少しコツが必要でした。
この記事ではGitHub Codespaces上で docker compose up
する方法を紹介します。
最小限のデモはこちら(実際にGitHub Codespacesで動作確認しました):
.devcontainer/ 以下のファイル
.devcontainer/devcontainer.json
各項目の詳細は以下の公式ドキュメントを見てください
{
"name": "Docker from Docker",
// .devcontainer/Dockerfile を指定します
"dockerFile": "./Dockerfile",
// Windows 10 Proだと管理者権限でVSCodeを起動しないと
// port 3000や5000が使えなくて罰なので
// port 30000とか50000にしています……
"forwardPorts": [30000, 50000],
// devcontainerのユーザーをroot以外にします(推奨)
"remoteUser": "user",
// devcontainer起動時にdocker runに渡されるオプション
"runArgs": ["--init"],
// Docker from Dockerを実現するためにはこれが必要です
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
// これを指定しないとDockerfileのCMDが勝手に
// "while sleep 1000; do :; done"
// に書き換えられます(マジ)
"overrideCommand": false,
// Docker from Dockerでホストファイルをマウントするために必要です
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
// 私はGNUを信仰しているのでデフォルトのシェルをbashにしていますがここはお好みでどうぞ
// ただしデフォルトのシェルを指定しないと/bin/shになって結構過酷です
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash"
}
},
"terminal.integrated.defaultProfile.linux": "bash"
}
}
}
}
.devcontainer/Dockerfile
アプリケーションのDockerfileをそのままdevcontainerのDockerfileに指定することもできますが、分けることをオススメします。
特にDocker from Dockerを実現する場合、以下のようにグチャグチャやる必要が生じるので。。
グチャグチャやってる部分に関しては以下のドキュメントからコピペしただけです:
# 開発用コンテナなのでubuntuでええやろ
FROM ubuntu:22.04
# 開発環境に必要なパッケージなどはここでインストールしておきます
# gitはGitHub Codespacesで必須です
# curlも次のステップで使うので必須です
RUN apt update && apt install -y \
git \
curl \
vim \
htop \
jq
# Docker from DockerするためにDockerをインストールします
RUN curl -fsSL https://get.docker.com | sh
# たとえばNode.jsのプロジェクトならここで開発用コンテナにもインストールしておく
RUN curl -Ls https://deb.nodesource.com/setup_18.x | bash
RUN apt update && apt install -y nodejs
# この二行なくてもdevcontainer.jsonのforwardPortsが優先されるのかもしれないけど一応書いてる
EXPOSE 30000
EXPOSE 50000
# 実際に開発に使うroot以外のユーザーを作成します
RUN useradd -m user
# dockerコマンドを上記のroot以外のユーザーでも使えるようにするためにグチャグチャやってます
ARG NONROOT_USER=user
RUN echo "#!/bin/sh\n\
sudoIf() { if [ \"\$(id -u)\" -ne 0 ]; then sudo \"\$@\"; else \"\$@\"; fi }\n\
SOCKET_GID=\$(stat -c '%g' /var/run/docker.sock) \n\
if [ \"${SOCKET_GID}\" != '0' ]; then\n\
if [ \"\$(cat /etc/group | grep :\${SOCKET_GID}:)\" = '' ]; then sudoIf groupadd --gid \${SOCKET_GID} docker-host; fi \n\
if [ \"\$(id ${NONROOT_USER} | grep -E \"groups=.*(=|,)\${SOCKET_GID}\(\")\" = '' ]; then sudoIf usermod -aG \${SOCKET_GID} ${NONROOT_USER}; fi\n\
fi\n\
exec \"\$@\"" > /usr/local/share/docker-init.sh \
&& chmod +x /usr/local/share/docker-init.sh
ENTRYPOINT [ "/usr/local/share/docker-init.sh" ]
CMD [ "sleep", "infinity" ]
アプリケーションのDockerfileとdocker-compose.yml
簡単のために一つのserviceを起動するdocker-compose.ymlにしますが、
複数のserviceを起動する場合でもちゃんと動きます。
frontend
というディレクトリにViteプロジェクトがあるという想定にしてみましょう。
npm create vite@latest frontend -- --template react-ts
cd frontend
npm i
frontend/Dockerfile
これは普通に書いてOKです。
たとえばViteのプロジェクトなら
FROM node:18-bullseye-slim
WORKDIR /app
COPY . /app
RUN npm ci
EXPOSE 30000
CMD ["npm", "run", "dev"]
みたいなもので良いでしょう。
frontend/package.json
npm run dev
で起動する際にport, hostを指定するように package.json
を書き換える必要があります。
"scripts": {
"dev": "vite --port 30000 --host 0.0.0.0",
"build": "tsc && vite build",
"preview": "vite preview --port 30000 --host 0.0.0.0"
},
Node.js / Vite以外の他のプログラミング言語やフレームワークでも、同様にhostを明示的にbindする必要があります。
docker-compose.yml
開発用に使うdocker-compose.ymlでは、ホスト側のファイルが書き換わったらDockerイメージ上のファイルも書き換わってほしいのでvolumeのbind mountを使うことが多いですが、Docker from Dockerの場合、ここに罠があるので注意が必要です!
version: "3.9"
services:
frontend:
build:
context: frontend
dockerfile: Dockerfile
volumes:
# ここが重要
# Docker from Dockerでは .:/app と書くと正常に動かない
# 相対パスではなく、フルパスで書く必要がある
# 一方でDockerの外でも動かしたいので、
# デフォルト値として相対パスを指定している
- type: bind
source: ${LOCAL_WORKSPACE_FOLDER:-.}/frontend
target: /app
command: npm run dev
ports:
- 30000:30000
networks:
- myapp
networks:
myapp:
name: myapp
使い方
- GitHub上でCodespacesを立ち上げる
- VSCodeでCodespacesを開く
- 統合ターミナルを立ち上げる
docker compose up
- http://localhost:30000/ を開く
Discussion
Docker in Docker について公式にサンプルがありました。
乗っかった方が不具合を踏みにくいかもしれない。
読んでいます。
こちらの記事を参考にさせていただき、GitHub CodespacesでDockerを動かすことができました。
ありがとうございます。
一点確認ですが、こちらにおけるdocker-compose.ymlに「target: /app」とありますが、正しくは「target: /src」ではないでしょうか?