DevcontainerでTiltの環境を作ってDocker Composeで記述したサービスを立ち上げる

固有名詞の多いタイトルで失礼します。

力強くブログを108記事アウトプットする日 に参加中の灰原です。 forceoutput.github.io

Devcontainer で Tilt の環境を作って Docker Compose で記述したサービスを立ち上げていきます。

なにをやるのか

Tilt (https://tilt.dev/)は、"A toolkit for fixing the pains of microservice development." と銘打たれた、ローカル環境で複数コンテナをうまく扱うためのものです。 Tilt は k8s 上に構築されたサービスをローカルで起動することを主たる目的にしていますが、Docker Compose で構築されたサービスも扱うことができます。

今回は、まず Devcontainer で Tilt そのものの環境を作り、そのうえで Docker Compose で記述されたサービスをローカルで動かしてみます。

Devcontainer の準備

Tilt を使うための Devcontainer を用意します。

Tilt のインストールは、ドキュメントにしたがって curl でインストールスクリプトを落としてきて、それを実行させることにします。 Install | Tilt

Tilt に加えて、Docker も必要になります。これには DinD (Docker in Docker) でやるか、DooD (Docker outside of Docker) でやるかの選択肢があります。 今回はあえて Docker 環境を分離するモチベーションが無いため、素直に DooD で構築します。

これらを鑑みて書いた devcontainer.json と Dockerfile がこちらになります。

https://github.com/w-haibara/tilt-multi-docker-compose/tree/8acb694e3881fb6ab972231b41d2bb6c411c5177/.devcontainer

devcontainer.json

// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-outside-of-docker
{
    "name": "Tilt Dev Container",
    "build": {
        "dockerfile": "Dockerfile"
    },

    "features": {
        "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
            "version": "latest",
            "enableNonRootDocker": "true",
            "moby": "true"
        }
    },

    // Use this environment variable if you need to bind mount your local source code into a new container.
    "remoteEnv": {
        "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
    }

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [],

    // Use 'postCreateCommand' to run commands after the container is created.
    // "postCreateCommand": "docker --version",

    // Configure tool-specific properties.
    // "customizations": {},

    // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    // "remoteUser": "root"
}

Dockerfile

FROM mcr.microsoft.com/devcontainers/base:ubuntu

RUN apt update && apt install -y xdg-utils
RUN curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash

これで VSCode で Devcontainer を開き、Tilt が実行できるようになりました。

サンプルアプリの準備

つぎに Tilt で起動させるサンプリアプリを準備します。 GET リクエストに対して "Hello, World!" を返す Python スクリプトを、シンプルにコンテナ化します。

https://github.com/w-haibara/tilt-multi-docker-compose/tree/8acb694e3881fb6ab972231b41d2bb6c411c5177/app1

app1.py

import http.server
import socketserver

PORT = 3000

class Handler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()
        self.wfile.write(b'Hello, World!')

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Serving on port {PORT}")
    httpd.serve_forever()

Dockerfile

FROM python:3.13-bookworm

WORKDIR /app

COPY app1.py /app/

EXPOSE 3000

CMD ["python", "app1.py"]

さらにこれを Docker Compose で記述します。

https://github.com/w-haibara/tilt-multi-docker-compose/blob/8acb694e3881fb6ab972231b41d2bb6c411c5177/docker-compose.yml

docker-compose.yml

services:
  app1:
    image: sample/app1
    container_name: sample_app1
    build: ./app1
    ports:
      - "3000:3000"

この段階で、docker compose up でサービスを起動できる状態になりました。

Tiltfile の準備

最後に Tiltfile を書いていきます。Tilt はこれを読んでサービスを起動することになります。

Tiltfile は Starlark という Python 方言で記述します。 Launching & Managing Resources | Tilt

今回使う Titlefile はこちら。

tilt-multi-docker-compose/Tiltfile at 8acb694e3881fb6ab972231b41d2bb6c411c5177 · w-haibara/tilt-multi-docker-compose · GitHub

Tiltfile

version_settings(constraint='>=0.33.21')

docker_compose('docker-compose.yml')

docker_build(
  'sample/app1',
  './app1',
  live_update = [
    sync('./app1', '/app'),

    restart_container()
  ])

dc_resource('app1', labels=["server"])hon

ここまでで、以下のようなファイルの配置になっています。

$ tree . -a -I ".git" 
.
├── .devcontainer
│   ├── Dockerfile
│   └── devcontainer.json
├── Tiltfile
├── app1
│   ├── Dockerfile
│   └── app1.py
└── docker-compose.yml

2 directories, 6 files

サービスを動かす

サービスを立ち上げてみます。Devcontainer のシェルで tilt up を実行します。

vscode ➜ /workspaces/tilt-multi-docker-compose (main) $ tilt up
Tilt started on http://localhost:10350/
v0.33.21, built 2024-11-08

(space) to open the browser
(s) to stream logs (--stream=true)
(t) to open legacy terminal mode (--legacy=true)
(ctrl-c) to exit
Opening browser: http://localhost:10350/

スペースを押して、ブラウザで Tilt の Web UI を開きます。

Tilt の WebUI

ここで Tiltfile が valid であり、サービスのコンテナを立ち上げることに成功していることがわかります。それぞれで何かエラーがあれば、ここにエラーやワーニングが表示されます。

Endpoints の欄にある localhost:3000 にアクセスすると、無事にサンプルアプリが動いていることがわかります。

サンプルアプリのレスポンス

Tilt の特長のひとつに、柔軟なライブリロードがあります。

先ほどの Tiltfile でも ./app1/ 配下のファイルに変更があったらコンテナを再起動させる記述をしています。これを試してみましょう。

app1.py で、レスポンスのメッセージを書き換えてみます。

レスポンスを書き換えてみる

これを保存すると、"1 File Changed: [app1/app1.py] • app1" というように、ファイルの変更が検知され、コンテナの再起動が走ります。

ファイルの変更が検知され、コンテナの再起動が走る

再度 localhost:3000 にアクセスすると、無事にレスポンスが更新されていることがわかります。

サンプルアプリのレスポンスが更新されている

このように、言語やフレームワークに関係なくライブアップデートを仕込むことができるのでは、Tilt の強みと言えましょう。

おわりに

DevcontainerでTiltの環境を作ってDocker Composeで記述したサービスを立ち上げる手順を紹介しました。 みなさんの Tilt 情報もお待ちしております。