English | 中文
Run standard Compose files on WSL Containers (
wslc). Adocker compose-style experience forwslc, until Microsoft ships an officialwslc compose.
wslc-compose up -d # main command (any shell)
wslc compose up -d # PowerShell sugar for the same thingwslc-compose loads compose.yaml with the official parser,
compose-spec/compose-go v2 (interpolation, multi-file merge,
profiles, env_file and extends are all handled upstream), then translates every service into typed
wslc command lines.
- No state file: all project state lives in container labels (
com.docker.compose.*), matching Docker Compose. - Incremental updates: driven by a config hash (
com.wslc.compose.config-hash); unchanged containers are kept. --dry-runanywhere: prints thewslccommands it would run, even on machines without wslc.--strict: fields wslc cannot implement become errors instead of warnings.- Single binary: native Windows exe (UPX-packed, ~1.8 MB), or run inside a WSL distro and drive
wslc.exe.
Status: preview (v0.1). Unit and golden tests cover every wslc interaction (mocked Runner). Verified on Windows 11 + wslc 3.0.1:
up/up -d/down -v/ps/logs/exec/run/build/pull/--scale, healthcheck waits, anonymous volumes and GPU (RTX 5060 Ti, CUDA). Please attach--dry-runoutput to issues.
- Install
wslc compose(PowerShell sugar)- Quick start
- Command reference
- Compose support matrix
- Dry-run example
- Design notes
- Known limitations
- Development
Requires Windows 11 + WSL 2.9.3 or later (ships wslc; upgrade with wsl --update).
In PowerShell (5.1 or 7, no admin needed):
irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1 | iexThe script:
- detects amd64 / arm64, downloads
wslc-compose-windows-<arch>.exefrom GitHub Releases and verifies it againstchecksums.txt; - installs it to
%LOCALAPPDATA%\Programs\wslc-compose\wslc-compose.exe(re-running upgrades in place); - adds that directory to the user PATH;
- dot-sources
wslc-compose.profile.ps1from the Windows PowerShell 5.1 and PowerShell 7 profiles, enablingwslc compose ...in both.
Open a new terminal, then:
wslc-compose version
wslc compose version # PowerShell onlyWith parameters (irm | iex cannot pass them, so use the scriptblock form):
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1))) -Version v0.1.2 -InstallDir D:\tools\wslc-compose| Parameter | Env var (for irm | iex) |
Meaning |
|---|---|---|
-Version |
WSLC_COMPOSE_VERSION |
Release tag, default latest |
-InstallDir |
WSLC_COMPOSE_INSTALL_DIR |
Install dir, default %LOCALAPPDATA%\Programs\wslc-compose |
-BaseUrl |
WSLC_COMPOSE_BASE_URL |
Releases root; point at a mirror or fork |
-Arch |
Force amd64 / arm64 |
|
-NoPath |
Do not modify the user PATH | |
-NoProfile |
Do not modify $PROFILE (no wslc compose) |
|
-Uninstall |
Remove the install dir, PATH entry and $PROFILE line |
If the execution policy is
Restricted(the Windows client default),$PROFILEis not loaded and the script suggestsSet-ExecutionPolicy -Scope CurrentUser RemoteSigned.wslc-composeitself is unaffected.
Uninstall:
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1))) -UninstallEvery release ships wslc-compose-{windows,linux}-{amd64,arm64}, the wrapper scripts and checksums.txt.
The amd64 binaries are packed with UPX; upx -d <file> restores the original if
your antivirus dislikes packed executables. Inside a WSL distro:
curl -fsSLo ~/.local/bin/wslc-compose \
https://github.com/DawnMagnet/wslc-compose-go/releases/latest/download/wslc-compose-linux-amd64
chmod +x ~/.local/bin/wslc-composeRequires Go 1.24+:
go install github.com/DawnMagnet/wslc-compose-go/cmd/wslc-compose@latest
# or
git clone https://github.com/DawnMagnet/wslc-compose-go && cd wslc-compose-go
make build # host platform -> bin/wslc-compose
make dist # all platforms + UPX + scripts + checksums.txt -> dist/ (UPX= to skip packing)The wslc executable is located via: --wslc → $WSLC_COMPOSE_BIN → wslc.exe / wslc on PATH
→ C:\Program Files\WSL\wslc.exe (/mnt/c/Program Files/WSL/wslc.exe inside WSL).
Inside a WSL distro, when calling wslc.exe, bind-mount sources are converted with wslpath -w and
forward slashes (/mnt/c/src/app → C:/src/app), because wslc treats backslashes as escapes.
wslc-compose is the real command. wslc is Microsoft's binary and has no plugin mechanism, so
wslc compose is provided by thin wrappers that forward compose ... to wslc-compose and every other
subcommand unchanged to the real wslc.exe:
| Shell | Setup |
|---|---|
| PowerShell | Done by install.ps1. Manually: add . <install dir>\wslc-compose.profile.ps1 to $PROFILE |
| bash / zsh (in WSL) | Add source <path>/wslc-compose.sh to ~/.bashrc (needs the Linux wslc-compose on PATH) |
| cmd.exe / batch | Put the directory holding wslc.cmd before C:\Program Files\WSL in PATH. The system PATH wins over the user PATH, so this needs admin; just use wslc-compose instead |
The PowerShell wrapper is intentionally not called wslc-compose.ps1: PowerShell prefers .ps1 over .exe
for the same name, so such a file would shadow wslc-compose.exe (the v0.1.0 bug).
wslc compose up -d
wslc compose logs -f web
wslc compose down -vWhen an official wslc compose ships, drop the wrapper; labels already match Docker Compose.
# compose.yaml
services:
web:
build: .
ports: ["8080:80"]
depends_on:
db: { condition: service_healthy }
db:
image: postgres:16-alpine
environment: { POSTGRES_PASSWORD: example }
volumes: [dbdata:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
volumes:
dbdata: {}wslc-compose up -d --dry-run # preview the wslc commands
wslc-compose up -d # networks/volumes, build, start in dependency order
wslc-compose ps
wslc-compose logs -f
wslc-compose exec db psql -U postgres
wslc-compose down -vGlobal flags (before or after the subcommand):
| Flag | Meaning |
|---|---|
-f, --file |
Compose file, repeatable (also COMPOSE_FILE) |
-p, --project-name |
Project name (also COMPOSE_PROJECT_NAME; default name: or directory name) |
--project-directory |
Working directory |
--profile |
Enable a profile, repeatable (also COMPOSE_PROFILES) |
--env-file |
Interpolation env file (default .env) |
--dry-run |
Print wslc commands only (commands on stdout, progress on stderr) |
--strict |
Treat unsupported fields as errors |
--wslc |
Path to the wslc executable |
--default-dns |
DNS injected when a service has no dns:; default 1.1.1.1, --default-dns= disables |
--parallel |
Concurrency for wslc queries (default 1, see Design notes) |
--ansi |
Colourised log prefixes: auto/always/never (honours NO_COLOR) |
| Command | Main flags | Behaviour |
|---|---|---|
up [SERVICE...] |
-d --build --no-build --pull --force-recreate --no-recreate --no-deps --remove-orphans --scale SVC=N --wait --wait-timeout -t |
Create networks/volumes → build/pull → converge containers in dependency order; attaches logs without -d (Ctrl+C stops). --scale overrides scale/deploy.replicas (repeatable, may be 0). Rolls back resources created by this run on failure |
down |
-v --remove-orphans -t |
Stop and remove containers in reverse dependency order, remove project networks; -v removes declared named volumes (not external ones) |
ps [SERVICE...] |
-a -q --services --status STATE (repeatable, implies -a) --format table|json |
List project containers; running containers with a healthcheck get a HEALTH column |
logs [SERVICE...] |
-f -n/--tail -t --since --until --no-log-prefix |
Merged multi-container logs with `name |
build [SERVICE...] |
--no-cache --pull |
Build every service with build: |
pull [SERVICE...] |
--ignore-pull-failures |
Pull images (each image once) |
config |
--services --volumes --networks --images --hash "*" --format yaml|json |
Print the normalised model or a projection; list modes print names only |
exec SERVICE [--] CMD... |
-i (default on) -t -T -d -u -w -e --index |
Run a command in a running container; TTY follows stdin; a leading -- is stripped (same for run) |
run SERVICE [CMD...] |
--rm -d --name --no-deps --service-ports -T -u -w -e --entrypoint --build |
One-off container (oneoff=True label); dependencies are started first |
start / stop / restart |
-t |
wslc has no restart; restart = stop + start |
version |
--short |
Show own and wslc versions |
✅ Mapped
| Compose field | wslc flags |
|---|---|
name, container_name, deploy.replicas/scale |
--name <project>-<service>-<n> or container_name |
image, build.context/dockerfile/args/target/labels/tags/no_cache/pull |
wslc build -t … -f … --build-arg … --target … -l … --no-cache --pull |
command, entrypoint |
--entrypoint <first> + image + remaining items + command |
environment, env_file |
-e K=V (env_file merged by compose-go, sorted by key) |
ports (host_ip, ranges, udp) |
-p [ip:]host:container[/udp] |
volumes bind / named / anonymous / tmpfs (with size), tmpfs, read-only mounts |
-v / --tmpfs; bind sources become Windows forward-slash paths. wslc rejects bare paths, so anonymous volumes (- /data) become project-scoped named volumes <project>_<service>_<path>_anon (kept across recreation, removed by down -v) |
networks (default <project>_default, aliases), network_mode: none |
--network + --network-alias <service> + aliases |
Top-level networks: driver, internal, ipam.config[0].subnet/gateway, driver_opts, labels, external, name |
wslc network create … |
Top-level volumes: name, external, labels |
wslc volume create -l com.docker.compose.project=… -l com.docker.compose.volume=… |
working_dir, user, hostname, domainname, labels |
-w -u -h --domainname -l |
dns, dns_search, dns_opt |
--dns --dns-search --dns-option |
mem_limit / deploy.resources.limits.memory, cpus / limits.cpus, shm_size |
-m 512M (upper-case units) --cpus --shm-size |
ulimits, stop_signal, stop_grace_period |
--ulimit --stop-signal --stop-timeout |
gpus, deploy.resources.reservations.devices[capabilities: gpu] |
--gpus all |
tty, stdin_open |
-t -i |
depends_on (started / healthy / completed_successfully / required) |
dependency order + polling wslc inspect |
profiles, pull_policy (always/missing/never/build) |
service selection / image strategy |
Interpolation, .env, multiple -f, extends, include |
handled natively by compose-go |
ℹ️ Mapped (verified on wslc 3.0.1)
| Field | Notes |
|---|---|
healthcheck |
--health-cmd/--health-interval/--health-timeout/--health-start-period/--health-retries, --no-healthcheck; CMD form is shell-quoted. ps reads HealthStatus from wslc list (falls back to inspect) |
depends_on: service_healthy |
Polls State.Health.Status from wslc inspect; if wslc never reports health, after 3 polls "running" counts as healthy, with a warning |
ports[].mode: host |
Published as a normal port (INFO, does not trip --strict) |
--strict)
restart, deploy.restart_policy, privileged, cap_add/cap_drop, devices, device_cgroup_rules,
security_opt, sysctls, extra_hosts, secrets, configs, logging, platform, init, read_only,
ipc, pid, uts, userns_mode, group_add, cgroup/cgroup_parent, runtime, isolation, mac_address,
links/external_links, volumes_from, storage_opt, oom_*, pids_limit, blkio_config,
cpu_shares/cpu_quota/cpuset etc., mem_reservation/memswap_limit, post_start/pre_stop, develop (watch),
provider, models, use_api_socket, network_mode: host|service:|container:,
multiple networks (only the highest-priority one is joined), static ipv4_address, volume nocopy/subpath,
npipe/image/cluster volume types,
build.secrets/ssh/platforms/cache_from/cache_to/additional_contexts/network/extra_hosts/dockerfile_inline,
healthcheck.start_interval, non-bridge network drivers, IPv6, volume drivers and options,
deploy.resources.reservations (memory).
❌ Unsupported commands: watch, attach, cp, top, pause/unpause, port, events, images,
scale (use up --scale), kill, rm, create, push, ls (multi-project).
$ wslc-compose -f minimal.yaml --dry-run up -d
wslc.exe network create -l com.docker.compose.network=default -l com.docker.compose.project=minimal minimal_default
wslc.exe pull nginx:alpine
wslc.exe run -d --name minimal-hello-1 -l com.docker.compose.container-number=1 -l com.docker.compose.oneoff=False -l com.docker.compose.project=minimal -l com.docker.compose.project.config_files=C:/src/demo/minimal.yaml -l com.docker.compose.project.working_dir=C:/src/demo -l com.docker.compose.service=hello -l com.wslc.compose.config-hash=<sha256> -l com.wslc.compose.version=dev -p 8080:80 --network minimal_default --network-alias hello --dns 1.1.1.1 nginx:alpine
$ wslc-compose --dry-run down -v
wslc.exe network remove minimal_defaultWith wslc present, dry-run really queries current state (list/inspect) and only skips mutations, so it
previews exactly which containers are kept or recreated. Without wslc it assumes an empty state.
See testdata/golden/; up_full.golden covers nearly every mapped field.
- Project state = container labels. Each container carries
com.docker.compose.project/service/container-number/oneoff/ project.working_dir/project.config_filespluscom.wslc.compose.config-hashandcom.wslc.compose.version.ps/downrely only onwslc list --filter label=..., falling back to per-containerinspectif labels are missing. - Config hash. JSON + SHA-256 of the service config, excluding
build,pull_policy,scale/replicas,depends_onandprofiles, so changing replica counts or dependencies does not recreate containers; services rebuilt byup --buildare always recreated. Inspect withwslc-compose config --hash "*". - Default DNS 1.1.1.1. The wslc utility VM forwards DNS to the Windows host resolver; on many LAN/corporate
networks containers then get
SERVFAILfor public names (apt/npm/pip fail). Services withoutdns:therefore get--dns 1.1.1.1; for internal names setdns:,--default-dns=10.0.0.53, or disable with--default-dns=. - Paths. On Windows everything becomes
C:/x/y; inside WSL/mnt/c/...is converted directly and other paths go throughwslpath -w(//wsl.localhost/<distro>/...). Relative Dockerfiles are resolved against the build context, because wslc resolves-frelative to its own working directory. - Upper-case memory units. wslc rejects
512mand only accepts512M, so all byte sizes useK/M/G. - Serialised + retried. The wslc preview may return
ERROR_SHARING_VIOLATIONunder concurrent calls andERROR_ALREADY_EXISTSwhen recreating a just-stopped container; short commands run serially and those errors are retried up to 5 times (2 s apart).pullalso retries registry hiccups (EOF, timeouts, resets, 429/502/503). wslc error output already streamed live is not repeated in the final error. - Rollback on failure. If
upfails midway (pull/build/start failure, unhealthy dependency), containers, networks and volumes created by this run are removed in reverse order; pre-existing resources are untouched. Failures in the--waitphase are not rolled back, so logs stay inspectable. - Deterministic order. Stable topological sort (ties by name); dry-run output and golden tests are reproducible.
Package layout: docs/architecture.md.
- wslc lacks key Compose capabilities: restart policies,
--privileged,--cap-add,--device,--platform,--network host, secrets/configs. These fields are ignored with a warning. - One network per container (wslc run accepts a single
--network); multi-network services need a different topology. wslc inspectoutput is OCI-style rather than Docker-style and is parsed tolerantly; if your wslc version renames fields,psstatus/ports orservice_healthywaits may degrade (with a warning).- Paths inside a WSL distro (not under
/mnt/<drive>) become//wsl.localhost/...UNC paths, whose acceptance depends on the wslc version; keep projects on a Windows drive. - Environment variables without a value (
environment: [TOKEN]with nothing set on the host) are skipped, because the wslc process runs on the Windows side. - Anonymous volumes become per-service named volumes, so replicas of a service share one (Docker gives each container its own).
- wslc's
--gpusonly acceptsall; GPUcount/device_idsare treated as all GPUs. --entrypointoverrides (run) are split on whitespace; quoting is not supported.scripts/wslc.cmddoes not handle complex quoted arguments; usewslc-composedirectly.
make test # unit + golden tests (no real wslc; Runner is mocked)
make race # race detector
make cover # coverage
make golden # rewrite testdata/golden after an intended output change
make lint # gofmt + go vet
make dist # all binaries (amd64 UPX-packed) + scripts + checksums.txtLayout:
cmd/wslc-compose/ entry point (signals, exit-code passthrough)
internal/cli/ cobra commands (argument parsing only)
internal/app/ use cases (up/down/ps/logs/exec/run/...)
internal/project/ compose-go loading, field policy, config hash
internal/translate/ ServiceConfig -> wslc argv (pure)
internal/plan/ desired vs actual -> actions; dependency order (pure)
internal/wslc/ Runner interface, typed client, dry-run, output parsing
internal/labels/ label keys and helpers
internal/paths/ Windows/WSL path conversion
internal/logs/ prefixed log multiplexing
internal/golden/ test helper (golden file comparison)
testdata/compose/ compose files used by tests
testdata/golden/ locked wslc command sequences
scripts/ install.ps1 and the `wslc compose` wrappers
.github/workflows/ ci.yml (test + build), release.yml (tag → release)
Adding a field mapping:
- Implement it in
internal/translateand use the field intestdata/compose/full.yaml; - If
internal/project/policy.gowarned about it, remove that rule; - Run
make goldenand review the diff; - Update the support matrix in this README (both languages).
Run make lint race before submitting. Real wslc --version and wslc <cmd> --help output is welcome for fixing mappings.
Releasing: write docs/release-notes/vX.Y.Z.md, then git tag vX.Y.Z && git push origin vX.Y.Z.
release.yml tests, cross-compiles, packs with UPX and publishes the GitHub Release (with checksums.txt).
Releases are published only by CI.
English | 中文
用标准 Compose 文件驱动 WSL Containers(
wslc) 的 Go 实现。 在微软官方wslc compose发布之前,提供docker compose风格的无缝体验。
wslc-compose up -d # 主命令(任意 shell)
wslc compose up -d # PowerShell 语法糖,等价wslc-compose 用官方解析器 compose-spec/compose-go v2
加载 compose.yaml(插值、多文件合并、profiles、env_file、extends 全部由官方实现处理),
再把每个服务翻译成类型化的 wslc 命令行调用。
- 零状态文件:项目状态全部存放在容器标签上(
com.docker.compose.*),与 Docker Compose 标签对齐。 - 增量更新:基于配置哈希(
com.wslc.compose.config-hash),配置不变的容器不会被重建。 - 随时
--dry-run:打印将要执行的wslc命令;即使本机没有 wslc 也能运行。 --strict:遇到 wslc 无法实现的字段直接报错,而不是静默忽略。- 单一可执行文件:Windows 原生 exe(UPX 压缩,约 1.8 MB),或在 WSL 发行版内运行并自动调用
wslc.exe。
状态:预览(v0.1)。单元/golden 测试覆盖全部 wslc 交互(mock Runner);并已在 Windows 11 + wslc 3.0.1 真机上回归
up/up -d/down -v/ps/logs/exec/run/build/pull/--scale、 健康检查等待、匿名卷与 GPU(RTX 5060 Ti,CUDA)。遇到差异欢迎附--dry-run输出提 issue。
需要 Windows 11 + WSL 2.9.3 及以上(自带 wslc,可用 wsl --update 升级)。
在 PowerShell(5.1 或 7 均可,无需管理员)中运行:
irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1 | iex脚本会:
- 自动识别 amd64 / arm64,从 GitHub Releases 下载最新的
wslc-compose-windows-<arch>.exe,并用checksums.txt校验 SHA-256; - 安装到
%LOCALAPPDATA%\Programs\wslc-compose\wslc-compose.exe(覆盖旧版本即为升级); - 把该目录加入用户 PATH;
- 在 Windows PowerShell 5.1 和 PowerShell 7 的 profile 中各加一行 dot-source
wslc-compose.profile.ps1, 让两种 PowerShell 里wslc compose ...都直接可用。
重新打开终端后:
wslc-compose version
wslc compose version # 仅 PowerShell带参数安装(irm | iex 无法传参,用 scriptblock 形式):
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1))) -Version v0.1.2 -InstallDir D:\tools\wslc-compose| 参数 | 环境变量(适用于 irm | iex) |
说明 |
|---|---|---|
-Version |
WSLC_COMPOSE_VERSION |
指定版本标签,默认 latest |
-InstallDir |
WSLC_COMPOSE_INSTALL_DIR |
安装目录,默认 %LOCALAPPDATA%\Programs\wslc-compose |
-BaseUrl |
WSLC_COMPOSE_BASE_URL |
Releases 根地址,可换成镜像或 fork |
-Arch |
强制 amd64 / arm64 |
|
-NoPath |
不修改用户 PATH | |
-NoProfile |
不修改 $PROFILE(不启用 wslc compose) |
|
-Uninstall |
删除安装目录、PATH 条目和 $PROFILE 中的那一行 |
若 PowerShell 执行策略为
Restricted(Windows 客户端默认),$PROFILE不会被加载,脚本会提示运行Set-ExecutionPolicy -Scope CurrentUser RemoteSigned。wslc-compose命令本身不受影响。
卸载:
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/DawnMagnet/wslc-compose-go/main/scripts/install.ps1))) -Uninstall每个 Release 都附带 wslc-compose-{windows,linux}-{amd64,arm64} 二进制、包装脚本和 checksums.txt。
amd64 二进制经 UPX 压缩;若杀毒软件误报,可用 upx -d <文件> 还原。
在 WSL 发行版内:
curl -fsSLo ~/.local/bin/wslc-compose \
https://github.com/DawnMagnet/wslc-compose-go/releases/latest/download/wslc-compose-linux-amd64
chmod +x ~/.local/bin/wslc-compose需要 Go 1.24+:
go install github.com/DawnMagnet/wslc-compose-go/cmd/wslc-compose@latest
# 或
git clone https://github.com/DawnMagnet/wslc-compose-go && cd wslc-compose-go
make build # 本机平台 -> bin/wslc-compose
make dist # 全部平台 + UPX 压缩 + 包装脚本 + checksums.txt -> dist/(UPX= 跳过压缩)wslc 可执行文件的查找顺序:--wslc 参数 → $WSLC_COMPOSE_BIN → PATH 中的 wslc.exe / wslc
→ C:\Program Files\WSL\wslc.exe(WSL 内为 /mnt/c/Program Files/WSL/wslc.exe)。
在 WSL 发行版里运行时,若调用的是 wslc.exe,bind mount 路径会自动经 wslpath -w 转换并改为正斜杠
(/mnt/c/src/app → C:/src/app),因为 wslc 把反斜杠视为转义字符。
主命令是 wslc-compose。wslc 是微软的二进制,无法注册子命令,因此提供三个轻量包装:compose ... 转给 wslc-compose,其他子命令原样转发给真正的 wslc.exe:
| 环境 | 做法 |
|---|---|
| PowerShell | install.ps1 已自动完成;手动方式:在 $PROFILE 中加入 . <安装目录>\wslc-compose.profile.ps1 |
| bash / zsh(WSL 内) | 在 ~/.bashrc 中加入 source <path>/wslc-compose.sh(需 PATH 中有 Linux 版 wslc-compose) |
| cmd.exe / 批处理 | 把 wslc.cmd 所在目录放到 PATH 中 C:\Program Files\WSL 之前。系统 PATH 优先于用户 PATH,因此需要管理员把它加进系统 PATH;一般直接用 wslc-compose 更省事 |
三个脚本都在仓库 scripts/ 下,也作为 Release 附件提供。PowerShell 包装刻意不叫 wslc-compose.ps1:同名时 PowerShell 优先 .ps1,会挡住 wslc-compose.exe(v0.1.0 的问题)。
之后即可:
wslc compose up -d
wslc compose logs -f web
wslc compose down -v当官方 wslc compose 发布后,删掉包装即可无缝切换——标签与 Docker Compose 保持一致。
# compose.yaml
services:
web:
build: .
ports: ["8080:80"]
depends_on:
db: { condition: service_healthy }
db:
image: postgres:16-alpine
environment: { POSTGRES_PASSWORD: example }
volumes: [dbdata:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
volumes:
dbdata: {}wslc-compose up -d --dry-run # 先看要执行的 wslc 命令
wslc-compose up -d # 创建网络/卷,构建镜像,按依赖顺序启动
wslc-compose ps
wslc-compose logs -f
wslc-compose exec db psql -U postgres
wslc-compose down -v全局参数(放在子命令前后均可):
| 参数 | 说明 |
|---|---|
-f, --file |
Compose 文件,可多次指定(亦支持 COMPOSE_FILE) |
-p, --project-name |
项目名(亦支持 COMPOSE_PROJECT_NAME,默认 name: 或目录名) |
--project-directory |
工作目录 |
--profile |
启用 profile,可多次(亦支持 COMPOSE_PROFILES) |
--env-file |
插值用的环境文件(默认读取 .env) |
--dry-run |
只打印 wslc 命令(输出到 stdout,进度信息到 stderr) |
--strict |
不支持的字段视为错误 |
--wslc |
wslc 可执行文件路径 |
--default-dns |
服务未声明 dns: 时注入的 DNS,默认 1.1.1.1;--default-dns= 关闭 |
--parallel |
wslc 查询并发数(默认 1,见设计要点) |
--ansi |
日志前缀着色:auto/always/never(遵循 NO_COLOR) |
| 命令 | 主要参数 | 行为 |
|---|---|---|
up [SERVICE...] |
-d --build --no-build --pull --force-recreate --no-recreate --no-deps --remove-orphans --scale SVC=N --wait --wait-timeout -t |
创建网络/卷 → 构建/拉取 → 依赖顺序收敛容器;非 -d 时附着日志,Ctrl+C 停止。--scale 覆盖 scale/deploy.replicas(可多次、可为 0)。失败时回滚本次新建的容器/网络/卷 |
down |
-v --remove-orphans -t |
逆依赖顺序停止并删除容器,删除项目网络;-v 删除声明的命名卷(external 不动) |
ps [SERVICE...] |
-a -q --services --status STATE(可多次,隐含 -a) --format table|json |
列出项目容器;声明了 healthcheck 的运行中容器会额外显示 HEALTH 列 |
logs [SERVICE...] |
-f -n/--tail -t --since --until --no-log-prefix |
多容器日志合并,带 `name |
build [SERVICE...] |
--no-cache --pull |
构建所有带 build: 的服务 |
pull [SERVICE...] |
--ignore-pull-failures |
拉取镜像(同一镜像只拉一次) |
config |
--services --volumes --networks --images --hash "*" --format yaml|json |
输出规范化模型或其投影;列表模式只输出名字(不打印 INFO/WARN) |
exec SERVICE [--] CMD... |
-i(默认开) -t -T -d -u -w -e --index |
在运行中的容器里执行命令;TTY 默认随 stdin 是否为终端;-- 分隔符会被去掉(run 同理) |
run SERVICE [CMD...] |
--rm -d --name --no-deps --service-ports -T -u -w -e --entrypoint --build |
一次性容器(oneoff=True 标签),默认先拉起依赖 |
start / stop / restart |
-t |
wslc 没有 restart,restart = stop + start |
version |
--short |
显示自身与 wslc 版本 |
✅ 已映射
| Compose 字段 | wslc 参数 |
|---|---|
name、container_name、deploy.replicas/scale |
--name <project>-<service>-<n> 或 container_name |
image、build.context/dockerfile/args/target/labels/tags/no_cache/pull |
wslc build -t … -f … --build-arg … --target … -l … --no-cache --pull |
command、entrypoint |
--entrypoint <首项> + 镜像 + 其余项 + command |
environment、env_file |
-e K=V(env_file 由 compose-go 合并,按键排序) |
ports(含 host_ip、范围展开、udp) |
-p [ip:]host:container[/udp] |
volumes bind / 命名卷 / 匿名卷 / tmpfs(含 size)、tmpfs、read_only 挂载 |
-v / --tmpfs,bind 源路径转换为 Windows 正斜杠形式。wslc 不接受裸路径,匿名卷(- /data)自动改写为项目内命名卷 <project>_<service>_<path>_anon(重建容器时数据保留,down -v 删除) |
networks(含默认网络 <project>_default、aliases)、network_mode: none |
--network + --network-alias <service> + aliases |
顶层 networks:driver、internal、ipam.config[0].subnet/gateway、driver_opts、labels、external、name |
wslc network create … |
顶层 volumes:name、external、labels |
wslc volume create -l com.docker.compose.project=… -l com.docker.compose.volume=… |
working_dir、user、hostname、domainname、labels |
-w -u -h --domainname -l |
dns、dns_search、dns_opt |
--dns --dns-search --dns-option |
mem_limit / deploy.resources.limits.memory、cpus / limits.cpus、shm_size |
-m 512M(自动大写单位)--cpus --shm-size |
ulimits、stop_signal、stop_grace_period |
--ulimit --stop-signal --stop-timeout |
gpus、deploy.resources.reservations.devices[capabilities: gpu] |
--gpus all |
tty、stdin_open |
-t -i |
depends_on(started / healthy / completed_successfully / required) |
依赖排序 + 轮询 wslc inspect 等待 |
profiles、pull_policy(always/missing/never/build) |
服务选择 / 镜像准备策略 |
插值、.env、多 -f 合并、extends、include |
由 compose-go 原生处理 |
ℹ️ 已映射(已在 wslc 3.0.1 真机验证)
| 字段 | 说明 |
|---|---|
healthcheck |
映射为 --health-cmd/--health-interval/--health-timeout/--health-start-period/--health-retries、--no-healthcheck;CMD 形式会被 shell 转义后拼接。ps 的 HEALTH 列读取 wslc list 的 HealthStatus(缺失时回退到 inspect) |
depends_on: service_healthy |
轮询 wslc inspect 的 State.Health.Status;若 wslc 不上报健康状态,连续 3 次后退化为“运行即视为健康”并给出警告 |
ports[].mode: host |
按普通端口发布处理(INFO 提示,不触发 --strict) |
--strict 时报错)
restart、deploy.restart_policy、privileged、cap_add/cap_drop、devices、device_cgroup_rules、
security_opt、sysctls、extra_hosts、secrets、configs、logging、platform、init、read_only、
ipc、pid、uts、userns_mode、group_add、cgroup/cgroup_parent、runtime、isolation、mac_address、
links/external_links、volumes_from、storage_opt、oom_*、pids_limit、blkio_config、
cpu_shares/cpu_quota/cpuset 等、mem_reservation/memswap_limit、post_start/pre_stop、develop(watch)、
provider、models、use_api_socket、network_mode: host|service:|container:、
多网络(只接入优先级最高的一个)、静态 ipv4_address、卷 nocopy/subpath、npipe/image/cluster 卷类型、
build.secrets/ssh/platforms/cache_from/cache_to/additional_contexts/network/extra_hosts/dockerfile_inline、
healthcheck.start_interval、非 bridge 网络驱动、IPv6、卷驱动及选项、deploy.resources.reservations(内存)。
❌ 不支持的命令:watch、attach、cp、top、pause/unpause、port、events、images、scale(请用 up --scale)、kill、rm、create、push、ls(多项目)。
$ wslc-compose -f minimal.yaml --dry-run up -d
wslc.exe network create -l com.docker.compose.network=default -l com.docker.compose.project=minimal minimal_default
wslc.exe pull nginx:alpine
wslc.exe run -d --name minimal-hello-1 -l com.docker.compose.container-number=1 -l com.docker.compose.oneoff=False -l com.docker.compose.project=minimal -l com.docker.compose.project.config_files=C:/src/demo/minimal.yaml -l com.docker.compose.project.working_dir=C:/src/demo -l com.docker.compose.service=hello -l com.wslc.compose.config-hash=<sha256> -l com.wslc.compose.version=dev -p 8080:80 --network minimal_default --network-alias hello --dns 1.1.1.1 nginx:alpine
$ wslc-compose --dry-run down -v
wslc.exe network remove minimal_default有 wslc 时,dry-run 会真实查询当前状态(list/inspect),只省略变更操作,
因此能准确预览“哪些容器保持、哪些重建”。没有 wslc 时按空状态预览。
更完整的例子见 testdata/golden/,其中 up_full.golden 覆盖了几乎全部映射字段。
- 项目状态 = 容器标签。 每个容器带有
com.docker.compose.project/service/container-number/oneoff/ project.working_dir/project.config_files以及com.wslc.compose.config-hash、com.wslc.compose.version。ps/down只依赖wslc list --filter label=...;若 list 输出缺少标签,则逐个inspect补全。 - 配置哈希。 对服务配置做 JSON + SHA-256,排除
build、pull_policy、scale/replicas、depends_on、profiles,避免只调整副本数或依赖时重建容器;up --build重新构建过的服务会强制重建。wslc-compose config --hash "*"可查看。 - 默认 DNS 1.1.1.1。 wslc 的工具 VM 把 DNS 转发到 Windows 主机解析器;在很多局域网/企业网络里,
容器内解析公网域名会得到
SERVFAIL(apt/npm/pip 失败)。因此对未声明dns:的服务注入--dns 1.1.1.1; 需要解析内网域名时,在服务里写dns:或使用--default-dns=10.0.0.53/--default-dns=关闭。 - 路径。 Windows 上统一转为
C:/x/y;WSL 内调用wslc.exe时/mnt/c/...直接换算, 其余路径经wslpath -w转为//wsl.localhost/<distro>/...。相对 Dockerfile 会按构建上下文解析成绝对路径, 因为 wslc 是相对自身工作目录解析-f的。 - 内存单位大写。 wslc 拒绝
512m,只接受512M,因此所有字节数都格式化为K/M/G大写后缀。 - 串行 + 重试。 wslc 预览版在并发调用时可能返回
ERROR_SHARING_VIOLATION,刚停止的容器重建时可能返回ERROR_ALREADY_EXISTS;短命令默认串行执行,并对这两类错误最多重试 5 次(间隔 2 秒)。pull另外对镜像仓库的网络抖动(EOF、超时、连接重置、429/502/503)重试。已实时显示过的 wslc 错误输出 不会在最终错误信息里再打印一次。 - 失败回滚。
up中途失败时(拉取/构建/启动失败、依赖不健康),按逆序删除本次创建的容器、网络和卷, 已存在的资源不受影响;--wait阶段的失败不回滚,便于查看日志。 - 确定性顺序。 依赖顺序使用稳定的拓扑排序(同层按名称),dry-run 输出与 golden 测试完全可复现。
更详细的包结构见 docs/architecture.md(英文)。
- wslc 对 Compose 关键能力缺失:没有重启策略、
--privileged、--cap-add、--device、--platform、--network host、secrets/configs,这些字段只能警告忽略。 - 每个容器只能接入一个网络(wslc run 只接受一个
--network),跨多个网络的服务需要调整拓扑。 wslc inspect输出遵循 OCI 风格而非 Docker 模式,解析采用多路径容错;若你的 wslc 版本字段名不同,ps的状态/端口列或service_healthy等待可能退化(会有警告)。- WSL 发行版内部路径(非
/mnt/<盘符>)会变成//wsl.localhost/...UNC 形式,wslc 是否接受取决于版本; 建议把项目放在 Windows 盘符下。 - 未声明值的环境变量(如
environment: [TOKEN]且宿主未设置)会被跳过,因为 wslc 进程运行在 Windows 侧。 - 匿名卷被改写为按服务命名的卷,因此同一服务的多个副本共享该卷(Docker 中每个容器各有一个)。
- wslc 的
--gpus只接受all,GPU 设备的count/device_ids会被当作全部 GPU。 --entrypoint覆盖(run)按空白拆分,不支持引号。scripts/wslc.cmd的参数转发不处理带引号的复杂参数,复杂场景请直接用wslc-compose。
make test # 单元 + golden 测试(无需真实 wslc,Runner 被 mock)
make race # 竞态检测
make cover # 覆盖率
make golden # 输出有意变化后重写 testdata/golden
make lint # gofmt + go vet
make dist # 全部平台二进制(amd64 经 UPX 压缩)+ 脚本 + checksums.txt项目结构:
cmd/wslc-compose/ 入口(信号处理、退出码透传)
internal/cli/ cobra 命令(只做参数解析)
internal/app/ 用例编排(up/down/ps/logs/exec/run/...)
internal/project/ compose-go 加载、字段策略、配置哈希
internal/translate/ ServiceConfig -> wslc argv(纯函数)
internal/plan/ 期望 vs 实际 -> 操作;依赖排序(纯函数)
internal/wslc/ Runner 接口、类型化客户端、dry-run、输出解析
internal/labels/ 标签键与辅助函数
internal/paths/ Windows/WSL 路径转换
internal/logs/ 带前缀的日志多路复用
internal/golden/ 测试辅助(golden 文件比对)
testdata/compose/ 测试用 compose 文件
testdata/golden/ 锁定的 wslc 命令序列
scripts/ install.ps1 与 `wslc compose` 包装脚本
.github/workflows/ ci.yml(测试 + 构建)、release.yml(打 tag 自动发布)
新增一个字段映射的步骤:
- 在
internal/translate中实现映射,并在testdata/compose/full.yaml中使用该字段; - 若该字段此前在
internal/project/policy.go中被警告,删除对应规则; make golden更新 golden 文件,检查 diff 是否符合预期;- 更新本 README 的支持矩阵(中英文两部分)。
提交前请确保 make lint race 通过。欢迎附上真机 wslc --version 与 wslc <cmd> --help 输出来校正映射。
发布新版本:编写 docs/release-notes/vX.Y.Z.md,然后 git tag vX.Y.Z && git push origin vX.Y.Z,
release.yml 会测试、交叉编译、UPX 压缩并创建 GitHub Release(附 checksums.txt)。Release 只由 CI 发布。