Ktor and Exposed
takeharak
JetBrains 公式 Kotlin LSP の alpha がリリースされたので、 Kotlin, Ktor, and Exposed な開発環境を Dev Container で構築してみる
今回の環境
TL;DR
1. ソースコードの取得
gh repo clone ktorio/ktor-documentation
Cloning into 'ktor-documentation'...
remote: Enumerating objects: 27093, done.
remote: Counting objects: 100% (1417/1417), done.
remote: Compressing objects: 100% (429/429), done.
remote: Total 27093 (delta 1201), reused 997 (delta 982), pack-reused 25676 (from 2)
Receiving objects: 100% (27093/27093), 91.09 MiB | 55.00 MiB/s, done.
Resolving deltas: 100% (15385/15385), done.
code ktor-documentation/codeSnippets/snippets/tutorial-server-db-integration
2. .devcontainer の追加
mkdir -p .devcontainer
// .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/java-postgres
+ {
+ "name": "tutorial-server-db-integration",
+ "dockerComposeFile": "compose.yaml",
+ "service": "app",
+ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ "features": {
+ "ghcr.io/devcontainers/features/java:1": {
+ "version": "21",
+ "jdkDistro": "jbr"
+ }
+ }
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // This can be used to network with other containers or with the host.
+ // "forwardPorts": [5432],
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ // "postCreateCommand": "java -version",
+
+ // Configure tool-specific properties.
+ // "customizations": {}
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+ }
+
// .devcontainer/devcontainer.env
+ POSTGRES_PASSWORD=postgres
+ POSTGRES_USER=postgres
+ POSTGRES_DB=postgres
+ POSTGRES_HOSTNAME=postgresdb
+
# .devcontainer/compose.yaml
+ services:
+ app:
+ container_name: javadev
+ image: mcr.microsoft.com/devcontainers/base:debian
+ env_file: devcontainer.env
+ # NOTE: POSTGRES_DB/USER/PASSWORD should match values in db container
+
+ volumes:
+ - ../..:/workspaces:cached
+
+ # Overrides default command so things don't shut down after the process ends.
+ command: sleep infinity
+
+ db:
+ container_name: postgresdb
+ image: postgres:latest
+ restart: unless-stopped
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+ env_file: devcontainer.env
+ # NOTE: POSTGRES_DB/USER/PASSWORD should match values in app container
+
+ # Runs db on the same network as the app container, allows "forwardPorts" in devcontainer.json function.
+ network_mode: service:app
+
+ # Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
+ # (Adding the "ports" property to this file will not forward from a Codespace.)
+
+ volumes:
+ postgres-data:
+
3. kotlin-lsp のインストール
mkdir -p .devcontainer/extensions
curl -sSLO --output-dir .devcontainer/extensions https://download-cdn.jetbrains.com/kotlin-lsp/0.252.17811/kotlin-0.252.17811.vsix
// .devcontainer/devcontainer.json
...
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "21",
"jdkDistro": "jbr"
}
- }
+. },
...
+ // Configure tool-specific properties.
- // "customizations": {}
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "${containerWorkspaceFolder}/.devcontainer/extensions/kotlin-0.252.17811.vsix"
+ ]
+ }
+ }
...
4. postgres の設定
mkdir -p .devcontainer/postgres/initdb.d
-- /Users/developer/workspaces/ktor-documentation/codeSnippets/snippets/tutorial-server-db-integration/.devcontainer/postgres/initdb.d/task.sql
+ DROP TABLE IF EXISTS task;
+ CREATE TABLE task(id SERIAL PRIMARY KEY, name VARCHAR(50), description VARCHAR(50), priority VARCHAR(50));
+
+ INSERT INTO task (name, description, priority) VALUES ('cleaning', 'Clean the house', 'Low');
+ INSERT INTO task (name, description, priority) VALUES ('gardening', 'Mow the lawn', 'Medium');
+ INSERT INTO task (name, description, priority) VALUES ('shopping', 'Buy the groceries', 'High');
+ INSERT INTO task (name, description, priority) VALUES ('painting', 'Paint the fence', 'Medium');
+ INSERT INTO task (name, description, priority) VALUES ('exercising', 'Walk the dog', 'Medium');
+ INSERT INTO task (name, description, priority) VALUES ('meditating', 'Contemplate the infinite', 'High');
+
# .devcontainer/compose.yaml
...
db:
container_name: postgresdb
image: postgres:latest
restart: unless-stopped
volumes:
+ - ./postgres/initdb.d:/docker-entrypoint-initdb.d:ro
- postgres-data:/var/lib/postgresql/data
...
// .devcontainer/devcontainer.env
- POSTGRES_PASSWORD=password
- POSTGRES_USER=postgres
- POSTGRES_DB=postgres
+ POSTGRES_PASSWORD=password
+ POSTGRES_USER=postgresql
+ POSTGRES_DB=ktor_tutorial_db
+ POSTGRES_HOSTNAME=postgresdb
+
5. Dev Container で実行する
```bash[class='command-line'][data-user='takeharak'][data-host='macbook-pro'][data-filter-continuation='(con)'][data-filter-output='(out)']
devcontainer open .
./gradlew run
Downloading https://services.gradle.org/distributions/gradle-8.4-bin.zip
............10%............20%.............30%............40%.............50%............60%.............70%............80%.............90%............100%
Welcome to Gradle 8.4!
Here are the highlights of this release:
- Compiling and testing with Java 21
- Faster Java compilation on Windows
- Role focused dependency configurations creation
For more details see https://docs.gradle.org/8.4/release-notes.html
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :run
2025-06-26 20:42:39.664 [main] INFO Application - Autoreload is disabled because the development mode is off.
2025-06-26 20:42:39.851 [main] INFO Application - Application started in 0.387 seconds.
2025-06-26 20:42:39.979 [DefaultDispatcher-worker-1] INFO Application - Responding at http://0.0.0.0:8080
6. 確認
open http://localhost:8080/static/index.html